First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // Media driver for MultiMediaCard Flash device
19 #include "pbusmedia.h"
20 #include <drivers/emmcptn.h>
22 #include "OstTraceDefinitions.h"
23 #ifdef OST_TRACE_COMPILER_IN_USE
24 #include "locmedia_ost.h"
26 #pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
28 #include "medmmcTraces.h"
31 #if defined(__DEMAND_PAGING__)
32 // If in debug mode, enable paging stats and their retrieval using DLocalDrive::EControlIO
34 #define __TEST_PAGING_MEDIA_DRIVER__
39 #ifndef BTRACE_PAGING_MEDIA
41 #define BTraceContext8(aCategory,aSubCategory,a1,a2)
42 #endif // BTRACE_PAGING_MEDIA
44 // Enable this macro to debug cache:
45 // NB The greater the number of blocks, the slower this is...
46 //#define _DEBUG_CACHE
48 #define __ASSERT_CACHE(c,p) (void)((c)||(p,0))
50 #define __ASSERT_CACHE(c,p)
54 GLREF_C TInt GetMediaDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry, TUint16& aReservedSectors, const TMMCard* aCardP);
55 GLREF_C TBool MBRMandatory(const TMMCard* aCardP);
56 GLREF_C TBool CreateMBRAfterFormat(const TMMCard* aCardP);
57 GLREF_C TInt BlockSize(const TMMCard* aCardP);
58 GLREF_C TInt EraseBlockSize(const TMMCard* aCardP);
59 GLREF_C TInt GetCardFormatInfo(const TMMCard* aCardP, TLDFormatInfo& aFormatInfo);
61 const TInt KStackNumber = 0;
63 const TInt KDiskSectorSize=512;
64 const TInt KDiskSectorShift=9;
66 const TInt KIdleCurrentInMilliAmps = 1;
68 const TInt KMBRFirstPartitionEntry=0x1BE;
71 inline T UMin(T aLeft,T aRight)
72 {return(aLeft<aRight ? aLeft : aRight);}
75 class DPhysicalDeviceMediaMmcFlash : public DPhysicalDevice
78 DPhysicalDeviceMediaMmcFlash();
80 virtual TInt Install();
81 virtual void GetCaps(TDes8& aDes) const;
82 virtual TInt Create(DBase*& aChannel, TInt aMediaId, const TDesC8* aInfo, const TVersion& aVer);
83 virtual TInt Validate(TInt aDeviceType, const TDesC8* aInfo, const TVersion& aVer);
84 virtual TInt Info(TInt aFunction, TAny* a1);
88 // these should be static const members of DMmcMediaDriverFlash, but VC doesn't support this
89 const TInt64 KInvalidBlock = -1;
90 const TInt KNoCacheBlock = -1;
92 class DMmcMediaDriverFlash : public DMediaDriver
95 DMmcMediaDriverFlash(TInt aMediaId);
96 ~DMmcMediaDriverFlash();
97 // ...from DMediaDriver
99 // replacing pure virtual
100 virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage*);
101 virtual TInt Request(TLocDrvRequest& aRequest);
102 virtual TInt PartitionInfo(TPartitionInfo& anInfo);
103 virtual void NotifyPowerDown();
104 virtual void NotifyEmergencyPowerDown();
105 // For creation by DPhysicalDeviceMediaMmcFlash
106 TInt DoCreate(TInt aMediaId);
111 EDRInUse = 0x0000, EDRStart, EDRNotPositive, EDREnd,
112 ELRRequest = 0x0010, ELRStart, ELRNotPositive, ELREnd, ELRCached,
113 EDWInUse = 0x0020, EDWStart, EDWNotPositive, EDWEnd,
114 EDFInUse = 0x0030, EDFStart, EDFNotPositive, EDFEnd, ENotMmcSocket,
115 ELWRequest = 0x0040, ELWStart, ELWFmtStAlign, ELWNotPositive, ELWEnd, ELWFmtEndAlign,
116 ELWLength, ELFStart, ELFEnd, ELFNotPositive,
118 EPCInUse = 0x0060, EPCFunc,
119 ESECBQueued = 0x0070,
120 EDSEDRequest = 0x0080, EDSEDNotErrComplete,
121 ECRReqIdle = 0x0090, ECRRequest,
122 ERRBStAlign = 0x00a0, ERRBStPos, ERRBNotPositive, ERRBEndAlign, ERRBEndPos,
123 ERRBOverflow, ERRBCchInv, ERRBExist,
124 ERWBStPos = 0x00b0, ERWBNotPositive, ERWBEndPos, ERWBOverflow, ERWBCchInv,
125 EMBStPos = 0x00c0, EMBStAlign, EMBNotPositive, EMBEndPos, EMBEndAlign,
126 EMBOverflow, EMBCchInvPre, EMBCchInvPost,
127 EBGAStPos = 0x00d0, EBGAStAlign, EBGANotPositive, EBGAEndPos, EBGAEndAlign,
128 EBGAOverflow, EBGACchInv,
129 EICMNegative = 0x00e0, EICMOverflow, ECMIOverflow,
130 EGCBAlign = 0x00f0, EGCBPos, EGCBCchInv,
132 ECFSessPtrNull = 0x0100, // Code Fault - session pointer NULL
134 EDBNotEven = 0x0110, // Not and even number of blocks in the buffer cache
135 EDBCBQueued = 0x0111, // The data transfer callback is already queued
136 EDBLength = 0x0112, // The length of data to transfer in data transfer callback is not positive
137 EDBLengthTooBig = 0x0113, // The length of data to transfer in data transfer callback is too big
138 EDBOffsetTooBig = 0x0114, // The Offset into the user data buffer is too big
139 EDBCacheInvalid = 0x0115, // The cache is invalid at the end of data transfer
140 EDBNotOptimal = 0x0116, // Due to Cache size DB functionality will never be utilised
141 ENoDBSupport = 0x0120, // DMA request arrived but PSL does not support double buffering
142 ENotDMAAligned = 0x0121,
144 static void Panic(TPanic aPnc);
155 EMReqWritePasswordData,
159 enum TMediaReqType {EMReqTypeNormalRd,EMReqTypeNormalWr,EMReqTypeUnlockPswd,EMReqTypeChangePswd};
161 enum {KWtRBMFst = 0x00000001, // iWtRBM - Read First Block only
162 KWtRBMLst = 0x00000002, // iWtRBM - Read Last Block only
163 KWtMinFst = 0x00000004, // iWtRBM - Write First Block only
164 KWtMinLst = 0x00000008, // iWtRBM - Write Last Block only
165 KIPCSetup = 0x00000010, // iRdROB - IPC Setup Next Iteration
166 KIPCWrite = 0x00000020}; // iRdROB - IPC Write Next Iteration
169 // MMC device specific stuff
173 TInt Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo);
175 inline DMMCStack& Stack() const;
176 inline TInt CardNum() const;
177 inline TMediaRequest CurrentRequest() const;
179 TInt LaunchRead(TInt64 aStart, TUint32 aLength);
181 TInt LaunchPhysRead(TInt64 aStart, TUint32 aLength);
183 TInt LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq);
184 TInt LaunchFormat(TInt64 aStart, TUint32 aLength);
186 TInt LaunchRPIUnlock(TLocalDrivePasswordData& aData);
187 TInt LaunchRPIRead();
188 TInt LaunchRPIErase();
189 TInt DecodePartitionInfo();
190 TInt WritePartitionInfo();
191 TInt GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry);
192 TInt CreateDefaultPartition();
195 #if defined __TEST_PAGING_MEDIA_DRIVER__
196 TInt HandleControlIORequest();
199 static void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors);
201 TInt CheckDevice(TMediaReqType aReqType);
203 static void SessionEndCallBack(TAny* aMediaDriver);
204 static void SessionEndDfc(TAny* aMediaDriver);
205 void DoSessionEndDfc();
207 static void DataTransferCallBack(TAny* aMediaDriver);
208 static void DataTransferCallBackDfc(TAny* aMediaDriver);
210 void DoReadDataTransferCallBack();
211 void DoWriteDataTransferCallBack();
212 void DoPhysReadDataTransferCallBack();
213 void DoPhysWriteDataTransferCallBack();
215 TInt AdjustPhysicalFragment(TPhysAddr &physAddr, TInt &physLength);
216 TInt PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength);
217 void PrepareNextPhysicalFragment();
219 TInt EngageAndSetReadRequest(TMediaRequest aRequest);
220 TInt EngageAndSetWriteRequest(TMediaRequest aRequest);
221 TInt EngageAndSetRequest(TMediaRequest aRequest, TInt aCurrent);
222 void CompleteRequest(TInt aReason);
224 TInt ReadDataUntilCacheExhausted(TBool* aAllDone);
225 TInt WriteDataToUser(TUint8* aBufPtr);
226 TInt ReadDataFromUser(TDes8& aDes, TInt aOffset);
227 TUint8* ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength);
228 TUint8* ReserveWriteBlocks(TInt64 aMedStart, TInt64 aMedEnd, TUint* aRBM);
229 void MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex);
230 void BuildGammaArray(TInt64 aStart, TInt64 aEnd);
231 void InvalidateCache();
232 void InvalidateCache(TInt64 aStart, TInt64 aEnd);
233 TUint8* IdxToCchMem(TInt aIdx) const;
234 TInt CchMemToIdx(TUint8* aMemP) const;
237 void PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData);
239 TInt AllocateSession();
242 TBool CacheInvariant();
243 TUint8* GetCachedBlock(TInt64 aAddr);
246 DMMCStack* iStack; // controller objects
248 DMMCSession* iSession;
253 TUint iBlkLenLog2; // cached CSD data
256 TBool iReadBlPartial;
257 TUint32 iPrWtGpLen; // preferred write group size in bytes,
260 TInt iReadCurrentInMilliAmps; // power management
261 TInt iWriteCurrentInMilliAmps;
263 TUint8* iMinorBuf; // MBR, CMD42, partial read
264 TUint8* iCacheBuf; // cached buffer
266 TInt iBlocksInBuffer;
267 TInt64* iCachedBlocks;
268 TInt* iGamma; // B lookup, ReserveReadBlocks()
269 TUint8* iIntBuf; // start of current buffer region
270 TInt iLstUsdCchEnt; // index of last used cache entry
272 TLocDrvRequest* iCurrentReq; // Current Request
273 TMediaRequest iMedReq;
275 TInt64 iReqStart; // user-requested start region
276 TInt64 iReqCur; // Currently requested start region
277 TInt64 iReqEnd; // user-requested end region
278 TInt64 iPhysStart; // physical region for one operation
279 TInt64 iPhysEnd; // physical end point for one operation
280 TInt64 iDbEnd; // Double buffer end point for one operation
282 TUint64 iEraseUnitMsk;
284 TUint iWtRBM; // Write - Read Before Modify Flags
285 TUint iRdROB; // Read - Read Odd Blocks Flags
292 TUint iHiddenSectors; // bootup / password
294 TMMCCallBack iSessionEndCallBack;
297 TPartitionInfo* iPartitionInfo;
298 TMMCMediaTypeEnum iMediaType;
299 TMMCEraseInfo iEraseInfo;
303 DMMCStack::TDemandPagingInfo iDemandPagingInfo;
305 #if defined(__TEST_PAGING_MEDIA_DRIVER__)
307 #endif // __TEST_PAGING_MEDIA_DRIVER__
309 TMMCCallBack iDataTransferCallBack; // Callback registered with the MMC stack to perform double-buffering
310 TDfc iDataTransferCallBackDfc; // ...and the associated DFC queue.
312 TBool iSecondBuffer; // Specified the currently active buffer
313 TBool iDoLastRMW; // ETrue if the last double-buffer transfer requires RMW modification
314 TBool iDoDoubleBuffer; // ETrue if double-buffering is currently active
315 TBool iDoPhysicalAddress; // ETrue if Physical Addressing is currently active
317 TBool iReadToEndOfCard; // {Read Only} ETrue if Reading to end of Card
321 DEMMCPartitionInfo* iMmcPartitionInfo; // Responsible for decoding partitions for embedded devices
324 // ======== DPhysicalDeviceMediaMmcFlash ========
327 DPhysicalDeviceMediaMmcFlash::DPhysicalDeviceMediaMmcFlash()
329 OstTraceFunctionEntry1( DPHYSICALDEVICEMEDIAMMCFLASH_DPHYSICALDEVICEMEDIAMMCFLASH_ENTRY, this );
330 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ctr"));
333 iVersion = TVersion(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
334 OstTraceFunctionExit1( DPHYSICALDEVICEMEDIAMMCFLASH_DPHYSICALDEVICEMEDIAMMCFLASH_EXIT, this );
338 TInt DPhysicalDeviceMediaMmcFlash::Install()
340 OstTraceFunctionEntry1( DPHYSICALDEVICEMEDIAMMCFLASH_INSTALL_ENTRY, this );
341 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ins"));
343 _LIT(KDrvNm, "Media.MmcF");
344 TInt r = SetName(&KDrvNm);
345 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_INSTALL_EXIT, this, r );
350 void DPhysicalDeviceMediaMmcFlash::GetCaps(TDes8& /* aDes */) const
352 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:cap"));
356 TInt DPhysicalDeviceMediaMmcFlash::Info(TInt aFunction, TAny* /*a1*/)
358 // Return the priority of this media driver
361 OstTraceExt2(TRACE_FLOW, DPHYSICALDEVICEMEDIAMMCFLASH_INFO_ENTRY ,"DPhysicalDeviceMediaMmcFlash::Info;aFunction=%d;this=%x", aFunction, (TUint) this);
362 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:info"));
363 if (aFunction==EPriority)
365 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_INFO_EXIT1, this, KMediaDriverPriorityNormal );
366 return KMediaDriverPriorityNormal;
368 // Don't close media driver when peripheral bus powers down. This avoids the need for Caps() to power up the stack.
369 if (aFunction==EMediaDriverPersistent)
371 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_INFO_EXIT2, this, KErrNone );
375 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_INFO_EXIT3, this, KErrNotSupported );
376 return KErrNotSupported;
379 TInt DPhysicalDeviceMediaMmcFlash::Validate(TInt aDeviceType, const TDesC8* /*aInfo*/, const TVersion& aVer)
381 OstTraceExt2(TRACE_FLOW, DPHYSICALDEVICEMEDIAMMCFLASH_VALIDATE_ENTRY ,"DPhysicalDeviceMediaMmcFlash::Validate;aDeviceType=%d;this=%x", aDeviceType, (TUint) this);
382 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:validate aDeviceType %d", aDeviceType));
383 if (!Kern::QueryVersionSupported(iVersion,aVer))
385 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_VALIDATE_EXIT1, this, KErrNotSupported );
386 return KErrNotSupported;
388 if (aDeviceType!=MEDIA_DEVICE_MMC)
390 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_VALIDATE_EXIT2, this, KErrNotSupported );
391 return KErrNotSupported;
394 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_VALIDATE_EXIT3, this, KErrNone );
398 TInt DPhysicalDeviceMediaMmcFlash::Create(DBase*& aChannel, TInt aMediaId, const TDesC8* /*aInfo*/, const TVersion& aVer)
400 // Create an MMC Card media driver.
403 OstTraceExt2(TRACE_FLOW, DPHYSICALDEVICEMEDIAMMCFLASH_CREATE_ENTRY, "DPhysicalDeviceMediaMmcFlash::Create;aMediaId=%d;this=%x", aMediaId, (TUint) this);
404 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:crt"));
406 if (!Kern::QueryVersionSupported(iVersion,aVer))
408 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_CREATE_EXIT1, this, KErrNotSupported );
409 return KErrNotSupported;
412 DMmcMediaDriverFlash* pD = new DMmcMediaDriverFlash(aMediaId);
417 r=pD->DoCreate(aMediaId);
419 pD->OpenMediaDriverComplete(KErrNone);
421 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:mdf"));
423 OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_CREATE_EXIT2, this, r );
428 // ======== DMmcMediaDriverFlash ========
431 void DMmcMediaDriverFlash::Panic(TPanic aPanic)
433 _LIT(KPncNm, "MEDMMC");
434 Kern::PanicCurrentThread(KPncNm, aPanic);
438 // ---- accessor functions -----
440 inline DMMCStack& DMmcMediaDriverFlash::Stack() const
441 { return *static_cast<DMMCStack*>(iStack); }
444 inline TInt DMmcMediaDriverFlash::CardNum() const
445 { return iCardNumber; }
448 inline DMmcMediaDriverFlash::TMediaRequest DMmcMediaDriverFlash::CurrentRequest() const
454 inline T* KernAlloc(const TUint32 n)
455 { return static_cast<T*>(Kern::Alloc(n * sizeof(T))); }
457 // ---- ctor, open, close, dtor ----
459 #pragma warning( disable : 4355 ) // this used in initializer list
460 DMmcMediaDriverFlash::DMmcMediaDriverFlash(TInt aMediaId)
461 :DMediaDriver(aMediaId),
463 iSessionEndCallBack(DMmcMediaDriverFlash::SessionEndCallBack, this),
464 iSessionEndDfc(DMmcMediaDriverFlash::SessionEndDfc, this, 1),
465 iMediaId(iPrimaryMedia->iNextMediaId),
466 iDataTransferCallBack(DMmcMediaDriverFlash::DataTransferCallBack, this),
467 iDataTransferCallBackDfc(DMmcMediaDriverFlash::DataTransferCallBackDfc, this, 1)
469 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:mmd"));
470 // NB aMedia Id = the media ID of the primary media, iMediaId = the media ID of this media
471 __KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash(), iMediaId %d, aMediaId %d\n", iMediaId, aMediaId));
472 OstTraceExt2( TRACE_FLOW, DMMCMEDIADRIVERFLASH_DMMCMEDIADRIVERFLASH, "> DMmcMediaDriverFlash::DMmcMediaDriverFlash;aMediaId=%d;iMediaId=%d", (TInt) aMediaId, (TInt) iMediaId );
476 #pragma warning( default : 4355 )
477 TInt DMmcMediaDriverFlash::DoCreate(TInt /*aMediaId*/)
479 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOCREATE_ENTRY, this );
480 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:opn"));
482 iSocket = ((DMMCSocket*)((DPBusPrimaryMedia*)iPrimaryMedia)->iSocket);
485 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT1, this, KErrNoMemory );
489 iCardNumber = ((DPBusPrimaryMedia*)iPrimaryMedia)->iSlotNumber;
491 iStack = iSocket->Stack(KStackNumber);
492 iCard = iStack->CardP(CardNum());
494 TMMCMachineInfo machineInfo;
495 Stack().MachineInfo(machineInfo);
496 TInt slotFlag = iCardNumber == 0 ? TMMCMachineInfo::ESlot1Internal : TMMCMachineInfo::ESlot2Internal;
497 iInternalSlot = machineInfo.iFlags & slotFlag;
499 __KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash::DoCreate() slotNumber %d iInternalSlot %d", iCardNumber, iInternalSlot));
500 OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_SLOT, "slotNumber=%d; iInternalSlot=%d", iCardNumber, iInternalSlot);
502 iSessionEndDfc.SetDfcQ(&iSocket->iDfcQ);
503 iDataTransferCallBackDfc.SetDfcQ(&iSocket->iDfcQ);
505 // check right type of card
506 if ((iMediaType=iCard->MediaType())==EMultiMediaNotSupported)
508 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT2, this, KErrNotReady );
512 // get card characteristics
513 const TCSD& csd = iCard->CSD();
514 iBlkLenLog2 = iCard->MaxReadBlLen();
515 iBlkLen = 1 << iBlkLenLog2;
516 iBlkMsk = (TInt64)(iBlkLen - 1);
518 SetTotalSizeInBytes(iCard->DeviceSize64());
521 // High capcity cards (block addressable, MMCV4.2, SD2.0) do not support partial reads
522 // ...some cards incorrectly report that they do, so ensure that we don't
524 iReadBlPartial = iCard->IsHighCapacity() ? EFalse : csd.ReadBlPartial();
526 // allocate and initialize session object
527 TInt r = AllocateSession();
530 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT3, this, r );
534 // get buffer memory from EPBUS
538 Stack().BufferInfo(buf, bufLen, minorBufLen);
542 // cache buffer can use rest of blocks in buffer. Does not have to be power of 2.
543 iCacheBuf = iMinorBuf + minorBufLen;
545 // We need to devide up the buffer space between the media drivers.
546 // The number of buffer sub-areas = number of physical card slots * number of media
547 bufLen-= minorBufLen;
548 DPBusPrimaryMedia* primaryMedia = (DPBusPrimaryMedia*) iPrimaryMedia;
549 TInt physicalCardSlots = iStack->iMaxCardsInStack;
550 TInt numMedia = primaryMedia->iLastMediaId - primaryMedia->iMediaId + 1;
551 TInt totalNumMedia = numMedia * physicalCardSlots;
553 TInt mediaIndex = iMediaId - primaryMedia->iMediaId;
554 TInt bufIndex = (iCardNumber * numMedia) + mediaIndex;
556 __KTRACE_OPT(KPBUSDRV, Kern::Printf("physicalCardSlots %d, iCardNumber %d\n", physicalCardSlots, iCardNumber));
557 OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_VARS1, "physicalCardSlots=%d; iCardNumber=%d", physicalCardSlots, iCardNumber);
558 __KTRACE_OPT(KPBUSDRV, Kern::Printf("iMediaId %d numMedia %d, mediaIndex %d, totalNumMedia %d, bufIndex %d\n",
559 iMediaId, numMedia, mediaIndex, totalNumMedia, bufIndex));
560 OstTraceExt5(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_VARS2, "iMediaId=%d; numMedia=%d; mediaIndex=%d; totalNumMedia=%d; bufIndex=%d", iMediaId, numMedia, mediaIndex, totalNumMedia, bufIndex);
562 __KTRACE_OPT(KPBUSDRV, Kern::Printf("bufLen1 %08X iCacheBuf1 %08X", bufLen, iCacheBuf));
563 OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_CACHEBUF1, "bufLen1=0x%08x; iCacheBuf1=0x%08x", (TUint) bufLen, (TUint) iCacheBuf);
564 bufLen/= totalNumMedia;
565 iCacheBuf+= bufIndex * bufLen;
566 __KTRACE_OPT(KPBUSDRV, Kern::Printf("bufLen2 %08X iCacheBuf2 %08X", bufLen, iCacheBuf));
567 OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_CACHEBUF2, "bufLen2=0x%08x; iCacheBuf2=0x%08x", (TUint) bufLen, (TUint) iCacheBuf);
569 iBlocksInBuffer = bufLen >> iBlkLenLog2; // may lose partial block
570 if(iSocket->SupportsDoubleBuffering())
572 // Ensure that there's always an even number of buffered blocks when double-buffering
573 iBlocksInBuffer &= ~1;
574 __ASSERT_DEBUG(iBlocksInBuffer >= 2, Panic(EDBNotEven));
577 * If Double-Buffering is enabled then the cache should not be greater than the maximum addressable range of the DMA controller,
578 * otherwise Double buffering will never be utilised because all transfers will fit into the cache.
580 const TUint32 maxDbBlocks = iSocket->MaxDataTransferLength() >> iBlkLenLog2;
583 __ASSERT_DEBUG(iBlocksInBuffer <= (TInt)maxDbBlocks, Panic(EDBNotOptimal));
588 iMaxBufSize = iBlocksInBuffer << iBlkLenLog2;
590 iPrWtGpLen = iCard->PreferredWriteGroupLength();
592 // check the preferred write group length is a power of two
593 if(iPrWtGpLen == 0 || (iPrWtGpLen & (~iPrWtGpLen + 1)) != iPrWtGpLen)
595 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT4, this, KErrNotReady );
599 __KTRACE_OPT(KPBUSDRV, Kern::Printf("iMaxBufSize %d iPrWtGpLen %d\n", iMaxBufSize, iPrWtGpLen));
600 OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_IPRWTGPLEN1, "iMaxBufSize=%d; iPrWtGpLen1=%d", iMaxBufSize, iPrWtGpLen);
601 // ensure the preferred write group length is as large as possible
602 // so we can write to more than one write group at once
603 while (iPrWtGpLen < (TUint32) iMaxBufSize)
606 // ensure preferred write group length is no greater than internal cache buffer
607 while (iPrWtGpLen > (TUint32) iMaxBufSize)
609 iPrWtGpMsk = TInt64(iPrWtGpLen - 1);
611 __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPrWtGpLen #2 %d\n", iPrWtGpLen));
612 OstTrace1(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_IPRWTGPLEN2, "iPrWtGpLen2=%d", iPrWtGpLen);
614 // allocate index for cached blocks
615 iCachedBlocks = KernAlloc<TInt64>(iBlocksInBuffer);
616 if (iCachedBlocks == 0)
618 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT5, this, KErrNoMemory );
623 iLstUsdCchEnt = iBlocksInBuffer - 1; // use entry 0 first
625 // allocate read lookup index
626 iGamma = KernAlloc<TInt>(iBlocksInBuffer);
629 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT6, this, KErrNoMemory );
633 // get current requirements
634 iReadCurrentInMilliAmps = csd.MaxReadCurrentInMilliamps();
635 iWriteCurrentInMilliAmps = csd.MaxWriteCurrentInMilliamps();
637 // get preferred erase information for format operations
638 const TInt err = iCard->GetEraseInfo(iEraseInfo);
641 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT7, this, err );
645 iEraseUnitMsk = TInt64(iEraseInfo.iPreferredEraseUnitSize) - 1;
647 // Retrieve the demand paging info from the PSL of the stack
648 Stack().DemandPagingInfo(iDemandPagingInfo);
650 // if a password has been supplied then it is sent when the partition info is read
653 // If this is an internal slot, then use the eMMC partition function
657 iMmcPartitionInfo = CreateEmmcPartitionInfo();
658 if(iMmcPartitionInfo == NULL)
660 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT8, this, KErrNoMemory );
663 TInt err = iMmcPartitionInfo->Initialise(this);
666 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT9, this, err );
671 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:opn"));
673 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT10, this, KErrNone );
677 void DMmcMediaDriverFlash::Close()
679 // Close the media driver - also called on media change
682 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_CLOSE_ENTRY );
683 __KTRACE_OPT(KPBUSDRV,Kern::Printf("=mmd:cls"));
686 iSessionEndDfc.Cancel();
687 iDataTransferCallBackDfc.Cancel();
688 CompleteRequest(KErrNotReady);
689 DMediaDriver::Close();
690 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_CLOSE_EXIT );
694 DMmcMediaDriverFlash::~DMmcMediaDriverFlash()
696 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_DMMCMEDIADRIVERFLASH_ENTRY );
697 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dtr"));
699 iSessionEndDfc.Cancel();
700 iDataTransferCallBackDfc.Cancel();
703 Kern::Free(iCachedBlocks);
706 delete iMmcPartitionInfo;
708 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dtr"));
709 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_DMMCMEDIADRIVERFLASH_EXIT );
713 TInt DMmcMediaDriverFlash::AllocateSession()
715 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_ENTRY, this );
718 // already allocated ?
719 if (iSession != NULL)
721 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_EXIT1, this, KErrNone );
725 iSession = iStack->AllocSession(iSessionEndCallBack);
726 if (iSession == NULL)
728 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_EXIT2, this, KErrNoMemory );
732 iSession->SetStack(iStack);
733 iSession->SetCard(iCard);
734 iSession->SetDataTransferCallback(iDataTransferCallBack);
738 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_EXIT3, this, KErrNone );
742 // ---- media access ----
744 TInt DMmcMediaDriverFlash::DoRead()
746 // set up iReqStart, iReqEnd and iReqCur and launch first read. Subsequent reads
747 // will be launched from the callback DFC.
750 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOREAD_ENTRY, this );
751 TInt r = CheckDevice(EMReqTypeNormalRd);
754 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOREAD_EXIT1, this, r );
758 const TInt64 pos(iCurrentReq->Pos());
759 TUint32 length(I64LOW(iCurrentReq->Length()));
761 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dr:0x%lx,0x%x", pos, length));
762 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DO_READ, "Position=0x%lx; Length=0x%x", (TUint) pos, (TUint) length);
763 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDRInUse));
764 __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDRStart));
765 __ASSERT_DEBUG(iCurrentReq->Length() >= 0, Panic(EDRNotPositive));
766 __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDREnd));
770 iReqCur = iReqStart = pos;
771 iReqEnd = iReqStart + length;
773 TBool allDone(EFalse);
774 if ( ((r = ReadDataUntilCacheExhausted(&allDone)) == KErrNone) && !allDone)
777 iPhysStart = iReqCur & ~iBlkMsk;
778 __ASSERT_DEBUG(I64HIGH(iPhysStart >> KMMCardHighCapBlockSizeLog2) == 0, Panic(ELRStart));
780 iReadToEndOfCard = ( iReqEnd >= TotalSizeInBytes() );
781 // Re-calculate length as some data may have been recovered from cache
782 length = I64LOW(iReqEnd - iReqCur);
784 if (iCurrentReq->IsPhysicalAddress() && !iReadToEndOfCard && (length >= iBlkLen) )
785 r = LaunchPhysRead(iReqCur, length);
786 else if ( (iReqEnd - iPhysStart) > iMaxBufSize && iSocket->SupportsDoubleBuffering() && !iReadToEndOfCard)
789 r = LaunchRead(iReqCur, length);
793 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOREAD_EXIT2, this, r );
800 #if defined(__DEMAND_PAGING__) && !defined(__WINS__)
801 if (DMediaPagingDevice::PageInRequest(*iCurrentReq))
803 r = iCurrentReq->WriteToPageHandler(NULL, 0, 0);
806 #endif // __DEMAND_PAGING__
808 TPtrC8 zeroDes(NULL, 0);
809 r = iCurrentReq->WriteRemote(&zeroDes,0);
813 // error occurred or read all from cache so complete immediately
817 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dr:%d", r));
819 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOREAD_EXIT3, this, r );
824 TInt DMmcMediaDriverFlash::LaunchRead(TInt64 aStart, TUint32 aLength)
826 // starts reads from DoRead() and the session end DFC. This function does not maintain the
827 // iReq* instance variables. It sets iPhysStart and iPhysEnd to the region that was actually
828 // read into iIntBuf. iIntBuf can be set to a cached entry or to the minor buffer. It is
829 // assumed that before this function is called that ReadDataUntilCacheExhausted() has been used.
832 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_LAUNCHREAD_ENTRY, this );
833 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHREAD, "position=0x%lx; length=0x%x", (TUint) iCurrentReq->Pos(), (TUint) I64LOW(iCurrentReq->Length()));
834 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lr:0x%lx,0x%x", aStart, aLength));
835 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELRStart));
836 __ASSERT_DEBUG(aLength > 0, Panic(ELRNotPositive));
837 __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELREnd));
838 __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ELRCached));
839 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
841 iDoPhysicalAddress = EFalse;
842 iDoDoubleBuffer = EFalse;
843 iSecondBuffer = EFalse;
846 // if this read goes up to the end of the card then use only
847 // single sector reads to avoid CMD12 timing problems
849 const TUint32 bufSize(iReadToEndOfCard ? iBlkLen : iMaxBufSize);
851 iPhysEnd = (UMin(iReqEnd, iPhysStart + bufSize) + iBlkMsk) & ~iBlkMsk;
853 TUint32 physLen(I64LOW(iPhysEnd - iPhysStart));
855 __ASSERT_DEBUG(I64HIGH(iPhysEnd - iPhysStart) == 0, Panic(ELREnd));
857 // partial reads must be within a single physical block
858 if (iReadBlPartial && physLen == iBlkLen && aLength <= (iBlkLen >> 1))
861 // Note : Partial reads are not supported for large block devices
862 // (MMCV4.2 and SD2.0 high capacity cards)
864 __ASSERT_DEBUG(I64HIGH(aStart) == 0, Panic(ELRStart));
865 __ASSERT_DEBUG(I64HIGH(aStart + aLength) == 0, Panic(ELREnd));
868 Stack().AdjustPartialRead(iCard, I64LOW(aStart), I64LOW(aStart + aLength), (TUint32*)&iPhysStart, (TUint32*)&iPhysEnd);
869 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, physLen >> KMMCardHighCapBlockSizeLog2);
873 iIntBuf = ReserveReadBlocks(iPhysStart, iPhysEnd, &physLen);
875 // EPBUSM automatically uses CMD17 instead of CMD18 for single block reads
876 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, physLen >> KMMCardHighCapBlockSizeLog2);
878 // Update Physical end point as less may have been required due to additional blocks found in cache during ReserveReadBlocks
879 iPhysEnd = iPhysStart + physLen;
882 TInt r = EngageAndSetReadRequest(EMReqRead);
884 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lr:%d", r));
885 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHREAD_EXIT, this, r );
889 TInt DMmcMediaDriverFlash::LaunchDBRead()
891 // starts reads from DoRead() and the session end DFC. This function does not maintain the
892 // iReq* instance variables. It sets iPhysStart and iPhysEnd to the region that was actually
893 // read into iIntBuf. iIntBuf can be set to a cached entry or to the minor buffer. It is
894 // assumed that before this function is called that ReadDataUntilCacheExhausted() has been used.
897 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_LAUNCHDBREAD_ENTRY, this );
898 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:ldbr:0x%lx,0x%x", iReqCur, I64LOW(iReqEnd - iReqCur)));
899 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHDBREAD, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur));
900 __ASSERT_DEBUG(TotalSizeInBytes() > iReqCur, Panic(ELRStart));
901 __ASSERT_DEBUG(I64LOW(iReqEnd - iReqCur) > 0, Panic(ELRNotPositive));
902 __ASSERT_DEBUG(TotalSizeInBytes() >= iReqEnd, Panic(ELREnd));
903 __ASSERT_CACHE(GetCachedBlock(iReqCur & ~iBlkMsk) == 0, Panic(ELRCached));
904 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
906 iDoDoubleBuffer = ETrue;
907 iDoPhysicalAddress = EFalse;
910 const TUint32 maxDbLength = iSocket->MaxDataTransferLength();
915 // If the PSL specifies a limit on the maximum size of a data transfer, then truncate the request...
917 iDbEnd = UMin(iDbEnd, iPhysStart + maxDbLength);
920 iDbEnd = (iDbEnd + iBlkMsk) & ~iBlkMsk;
922 const TUint32 doubleBufferSize = iMaxBufSize >> 1;
923 iPhysEnd = (iReqCur + doubleBufferSize) & ~iBlkMsk; // The end of the first double-buffered transfer
926 // If we're double-buffering, then the entire cache will be re-used
927 // continuously. Rather than continually reserve blocks during each
928 // transfer we calculate the blocks that will be present after all
929 // transfers have completed.
930 // @see DoSessionEndDfc()
935 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW(iDbEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2);
937 iSession->EnableDoubleBuffering(doubleBufferSize >> KDiskSectorShift);
939 // ...and switch to the 'second' buffer, which will be populated in the
940 // data transfer callback in parallel with hardware transfer of the first.
941 iSecondBuffer = ETrue;
943 TInt r = EngageAndSetReadRequest(EMReqRead);
945 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:ldbr:%d", r));
947 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHDBREAD_EXIT, this, r );
952 TInt DMmcMediaDriverFlash::LaunchPhysRead(TInt64 aStart, TUint32 aLength)
954 // This function does not maintain the iReq* instance variables.
955 // It is assumed that before this function is called that
956 // ReadDataUntilCacheExhausted() has been used.
959 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_LAUNCHPHYSREAD_ENTRY, this );
960 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHPHYSREAD, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur));
961 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:physr:0x%lx,0x%x", aStart, aLength));
962 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELRStart));
963 __ASSERT_DEBUG(aLength > 0, Panic(ELRNotPositive));
964 __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELREnd));
965 __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ELRCached));
966 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
970 iDoPhysicalAddress = ETrue;
971 iDoDoubleBuffer = EFalse;
973 // Local Media Subsystem ensures DMA Addressable range not exceeded.
974 // @see LocDrv::RegisterDmaDevice()
975 iPhysEnd = (iReqEnd + iBlkMsk) & ~iBlkMsk;
978 iFragOfset = iIPCLen = iNxtIPCLen = iBufOfset = 0;
980 // Determine if start/end are block aligned
981 // physical memory can only read the exact amount, not more!
982 const TBool firstPartial( (aStart & iBlkMsk) != 0);
984 TPhysAddr physAddr(0);
986 TUint32 physLen(I64LOW(iPhysEnd - iPhysStart));
990 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:physr:FirstPartial"));
991 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCH_PHYSREAD_FP, "FirstPartial");
992 // first index does not start on block boundary
993 // iIntBuf linear address is used for IPC within DoReadDataTransferCallBack()
996 iIntBuf = ReserveReadBlocks(iPhysStart, iPhysStart+iBlkLen,(TUint32*)&physLength);
997 #if !defined(__WINS__)
998 physAddr = Epoc::LinearToPhysical((TLinAddr)iIntBuf);
1000 physAddr = (TPhysAddr)iIntBuf;
1002 // Set SecondBuffer flag to indicate IPC cannot be done on next callback
1003 iSecondBuffer = ETrue;
1004 iBufOfset = I64LOW(iReqStart - iPhysStart);
1005 //iReqCur already set in DoRead;
1006 iFragOfset = iNxtIPCLen = physLength - iBufOfset;
1010 // Determine offset from start due to data possibly recovered from local cache
1011 iFragOfset = I64LOW(aStart - iReqStart);
1012 r = PrepareFirstPhysicalFragment(physAddr, physLength, aLength);
1014 // No use for secondBuffer yet...
1015 iSecondBuffer = EFalse;
1021 iPhysEnd = iPhysStart + physLength;
1023 if ((TUint32)physLength > physLen) physLength = physLen; // more memory in chunk than required
1025 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), (TUint8*)physAddr, physLen >> KMMCardHighCapBlockSizeLog2);
1027 iSession->Command().iFlags|= KMMCCmdFlagPhysAddr;
1028 iSession->EnableDoubleBuffering(physLength >> KDiskSectorShift);
1030 r = EngageAndSetReadRequest(EMReqRead);
1033 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lphysr:%d", r));
1035 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHPHYSREAD_EXIT, this, r );
1040 TInt DMmcMediaDriverFlash::DoWrite()
1042 // set up iReqStart, iReqEnd, and iReqCur, and launch first write. Any subsequent
1043 // writes are launched from the session end DFC. LaunchWrite() handles pre-reading
1044 // any sectors that are only partially modified.
1047 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOWRITE_ENTRY, this );
1048 const TInt64 pos = iCurrentReq->Pos();
1049 const TUint32 length = I64LOW(iCurrentReq->Length());
1051 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dw:0x%lx,0x%x", pos, length));
1052 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOWRITE, "position=0x%lx; length=0x%x", (TUint) pos, (TUint) length);
1053 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDWInUse));
1054 __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDWStart));
1055 __ASSERT_DEBUG(length > 0, Panic(EDWNotPositive));
1056 __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDWEnd));
1058 iReqCur = iReqStart = pos;
1059 iReqEnd = iReqStart + length;
1061 // iWtRBM is zero on construction because CBase-derived, and cleared at end
1062 // of successful writes. If a write does not complete successfully, it may
1063 // be left in non-zero state.
1066 iSecondBuffer = EFalse;
1067 iDoLastRMW = EFalse;
1068 iDoDoubleBuffer= EFalse;
1069 iDoPhysicalAddress = EFalse;
1071 const TInt r = LaunchWrite(iReqStart, length, EMReqWrite);
1073 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dw:%d", r));
1075 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOWRITE_EXIT, this, r );
1080 TInt DMmcMediaDriverFlash::DoFormat()
1082 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOFORMAT_ENTRY, this );
1083 const TInt64 pos = iCurrentReq->Pos();
1084 const TUint32 length = I64LOW(iCurrentReq->Length());
1086 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:df:0x%lx,0x%x", pos, length));
1087 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOFORMAT, "position=0x%lx; length=0x%x", (TUint) pos, (TUint) length);
1088 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDFInUse));
1089 __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDFStart));
1090 __ASSERT_DEBUG(length > 0, Panic(EDFNotPositive));
1091 __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDFEnd));
1093 iReqCur = iReqStart = pos & ~iBlkMsk;
1094 iReqEnd = (iReqStart + length + iBlkMsk) & ~iBlkMsk;
1096 // the cache isn't maintained during a format operation to avoid redundantly
1097 // writing 0xff to memory (the blocks won't be re-used.)
1100 // create an MBR after the first format step (or second if misaligned)
1104 iCreateMbr = EFalse;
1108 if (iReqStart == (TInt64(iHiddenSectors) << KDiskSectorShift) && CreateMBRAfterFormat(iCard))
1112 const TInt r = LaunchFormat(iReqStart, I64LOW(iReqEnd - iReqStart));
1114 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:df:%d", r));
1116 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOFORMAT_EXIT, this, r );
1121 TInt DMmcMediaDriverFlash::LaunchFormat(TInt64 aStart, TUint32 aLength)
1123 // starts writes from DoWrite(), DoFormat() and the session end DFC. This function does not
1124 // maintain the iReq* instance variables. It sets iIntBuf, iPhysStart and iPhysEnd.
1127 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_LAUNCHFORMAT_ENTRY, this );
1128 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHFORMAT, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur));
1129 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lf:0x%lx,0x%x", aStart, aLength));
1130 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELFStart));
1131 __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(ELWFmtStAlign));
1132 __ASSERT_DEBUG(aLength > 0, Panic(ELFNotPositive));
1133 __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELFEnd));
1134 __ASSERT_DEBUG((aLength & iBlkMsk) == 0, Panic(ELWFmtEndAlign));
1135 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
1139 if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone)
1141 iPhysStart = aStart & ~iBlkMsk;
1143 // formats are always block-aligned, and the buffer is initialized to 0xff
1144 // Check whether erase commands are supported by this card
1145 if (iCard->CSD().CCC() & KMMCCmdClassErase)
1147 // Determine the erase end point for the next command. We don't erase past the preferred erase unit
1148 // size. Therefore, check which is lower, the preferred erase unit size or the end of the requested range.
1149 TInt64 prefEraseUnitEnd = (iPhysStart + iEraseInfo.iPreferredEraseUnitSize) & ~iEraseUnitMsk;
1150 iPhysEnd = UMin(prefEraseUnitEnd, aStart + aLength);
1152 const TUint32 minEraseSectorSize=iEraseInfo.iMinEraseSectorSize;
1153 const TInt64 minEraseSecMsk = TInt64(minEraseSectorSize-1);
1155 // If erase start point doesn't lie on a min. erase unit boundary, then truncate the erase endpoint to
1156 // the next min. erase unit boundary (assuming requested range allows this)
1157 if ((iPhysStart & minEraseSecMsk)!=0)
1159 prefEraseUnitEnd=(iPhysStart+minEraseSectorSize) & ~minEraseSecMsk;
1160 iPhysEnd=UMin(prefEraseUnitEnd,iPhysEnd);
1163 // Otherwise, if calculated erase end point doesn't lie on a min. erase unit boundary, but is at least one
1164 // min. erase unit beyond the erase start point then move erase endpoint back to last min. erase unit boundary
1165 else if ((iPhysEnd & minEraseSecMsk)!=0 && (iPhysEnd & ~minEraseSecMsk)>iPhysStart)
1167 iPhysEnd&=(~minEraseSecMsk);
1170 // Now, if the erase start/end points are aligned to a min. erase unit boundary, we can use an erase cmd.
1171 if ((iPhysStart & minEraseSecMsk) == 0 && (iPhysEnd & minEraseSecMsk) == 0)
1174 // Check that erase commands are supported prior to issuing an erase command
1175 if(iEraseInfo.EraseGroupCmdsSupported())
1177 iSession->SetupCIMEraseMGroup(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2),
1178 I64LOW((iPhysEnd-iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD35/36/38 (Erase Group)
1182 iSession->SetupCIMEraseMSector(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2),
1183 I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD32/33/38 (Erase Sector)
1188 // Misaligned erase - use multi-block write. However, first - check write length doesn't exceed buffer size.
1189 if ((iPhysEnd-iPhysStart)>(TUint32)iMaxBufSize)
1191 iPhysEnd=(iPhysStart+iMaxBufSize);
1194 __ASSERT_DEBUG((iPhysEnd - iPhysStart) > 0, Panic(ELWLength));
1195 const TUint32 writeLen = I64LOW(iPhysEnd - iPhysStart);
1196 memset (iCacheBuf, 0x00, writeLen);
1197 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2);
1202 // Write to end of current write group, or end of request range, whichever is lower
1203 const TInt64 prefEraseUnitEnd = (iPhysStart + iPrWtGpLen) & ~iPrWtGpMsk;
1204 iPhysEnd = Min(prefEraseUnitEnd, aStart + aLength);
1206 __ASSERT_DEBUG((iPhysEnd - iPhysStart) > 0, Panic(ELWLength));
1207 const TUint32 writeLen = I64LOW(iPhysEnd - iPhysStart);
1208 memset (iCacheBuf, 0x00, writeLen);
1209 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2);
1212 r = EngageAndSetWriteRequest(EMReqFormat);
1214 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHFORMAT_EXIT, this, r );
1220 TInt DMmcMediaDriverFlash::LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq)
1222 // starts writes from DoWrite(), DoFormat() and the session end DFC. This function does not
1223 // maintain the iReq* instance variables. It sets iIntBuf, iPhysStart and iPhysEnd.
1226 OstTraceExt4(TRACE_FLOW, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_ENTRY, "DMmcMediaDriverFlash::LaunchWrite;aStart=%Ld;aLength=%x;aMedReq=%d;this=%x", aStart, (TUint) aLength, (TInt) aMedReq, (TUint) this);
1227 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur));
1228 __KTRACE_OPT(KPBUSDRV, Kern::Printf("\n>mmd:lw:0x%lx,%d,%d", aStart, aLength, aMedReq));
1229 __ASSERT_DEBUG(aMedReq == EMReqWrite || aMedReq == EMReqFormat, Panic(ELWRequest));
1230 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELWStart));
1231 __ASSERT_DEBUG(!(aMedReq == EMReqFormat) || (aStart & iBlkMsk) == 0, Panic(ELWFmtStAlign));
1232 __ASSERT_DEBUG(aLength > 0, Panic(ELWNotPositive));
1233 __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELWEnd));
1234 __ASSERT_DEBUG(!(aMedReq == EMReqFormat) || (aLength & iBlkMsk) == 0, Panic(ELWFmtEndAlign));
1235 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
1239 if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone)
1241 iPhysStart = aStart & ~iBlkMsk;
1243 // PSL MUST support double-buffering for DMA requests
1244 // first write, or have just completed previous write
1247 if(iDoDoubleBuffer == EFalse)
1250 // Can we use double-buffering for this request?
1252 // - Only if PSL supports double buffering and the request length
1253 // is greater than the maximum PSL buffer size.
1255 iDoPhysicalAddress = iCurrentReq->IsPhysicalAddress();
1257 TInt64 medEnd = aStart + aLength;
1259 TInt64 maxPslEnd = medEnd;
1260 const TUint32 maxDbLength = iSocket->MaxDataTransferLength();
1265 // If the PSL specifies a limit on the maximum size of a data transfer, then truncate the request...
1267 maxPslEnd = UMin(medEnd, iPhysStart + maxDbLength);
1270 iPhysEnd = (maxPslEnd + iBlkMsk) & ~iBlkMsk;
1272 if (iDoPhysicalAddress)
1274 iDoDoubleBuffer = EFalse;
1275 iIntBuf = ReserveWriteBlocks(aStart, medEnd, &iWtRBM);
1276 iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk;
1279 if (!iDoPhysicalAddress)
1281 iDoDoubleBuffer = iSocket->SupportsDoubleBuffering() && ((iPhysEnd - iPhysStart) > iMaxBufSize);
1285 // Conditions for double-buffering are met. Set up the size of the first
1286 // transfer to half the size of the block cache.
1288 // Note that we don't bother to align to write groups here, as the entire
1289 // request will be processed under one multi-block command so there's no
1290 // danger of forcing the card into RMW cycles as would be the case when
1291 // issuing multiple misaligned commands.
1293 iDbEnd = maxPslEnd; // The end of the complete double-buffered transfer
1294 iPhysEnd = (iPhysStart + (iMaxBufSize >> 1) + iBlkMsk) &~ iBlkMsk; // The end of the first double-buffered transfer
1295 __ASSERT_DEBUG(iPhysEnd - iPhysStart <= (iMaxBufSize >> 1), Panic(ELWLength));
1298 // Now reserve write blocks from the buffer cache. When double-buffering,
1299 // write blocks are only really reserved during the last transfer to avoid
1300 // continuously updating the cache indexes. Since the block cache is
1301 // continuously recycled, the following call shall invalidate the cache
1302 // and inform us as to whether we need to perform an RMW operation for
1303 // the first and last blocks prior to initiating data transfer.
1305 iIntBuf = ReserveWriteBlocks(aStart, iDbEnd, &iWtRBM);
1309 if ( (iPhysEnd - iPhysStart) > iMaxBufSize)
1312 // reserve buffers to end of first write group, or end of request range,
1313 // whichever is lower. Note that if the range already exists in the buffer,
1314 // e.g. because of a previous RBM, the same range will be returned. This
1315 // means that iWtRBM can be set to zero in the callback DFC, and this code
1316 // will retrieve the reserved range.
1318 const TInt64 wtGpEnd = (iPhysStart + iPrWtGpLen) & ~iPrWtGpMsk;
1319 medEnd = UMin(wtGpEnd, aStart + aLength);
1320 iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk;
1323 iIntBuf = ReserveWriteBlocks(aStart, medEnd, &iWtRBM);
1325 } //if (!iDoPhysicalAddress)
1326 } //if(iDoDoubleBuffer == EFalse)
1327 } //if (iWtRBM == 0)
1329 if (iWtRBM & KWtRBMFst)
1331 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw: read-before-modify required on first block"));
1332 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_RBMF, "Read-before-modify required on first block");
1333 if (iDoPhysicalAddress)
1334 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iMinorBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2);
1336 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2);
1337 r = EngageAndSetReadRequest(aMedReq);
1338 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT1, this, r );
1342 else if (iWtRBM & KWtRBMLst)
1344 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw: read-before-modify required on last block"));
1345 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_RBML, "Read-before-modify required on last block");
1346 if(iDoDoubleBuffer || iDoPhysicalAddress)
1349 // When double-buffering, the result of the RMW-read operation shall be stored
1350 // in the minor buffer, otherwise the data would be overwritten before the last
1351 // data transfer takes place.
1353 const TInt64 lastBlock = (aStart + aLength) & ~iBlkMsk; // start posn in media to read from (we know aStart + aLength isn't block aligned due to KWtRBMLst flag)
1354 if (iDoDoubleBuffer)
1355 iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iMinorBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2);
1357 iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iCacheBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2);
1362 // If not double-buffering, we can read the RMW data of the last block directly
1363 // into the block cache as we know that the data transfer will fit entirely
1364 // within the cache..
1366 const TInt64 lastBlock = iPhysEnd - iBlkLen; // start posn in media to read from
1367 iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iIntBuf + (lastBlock - iPhysStart), iBlkLen >> KMMCardHighCapBlockSizeLog2);
1370 // Kick off the RMW-read operation for the last block...
1371 r = EngageAndSetReadRequest(aMedReq);
1372 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT2, this, r );
1376 if (iWtRBM & KWtMinFst)
1378 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:Phys write-first-block-only"));
1379 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_FBO, "Write first block only");
1380 //Overwrite first block with the new data
1381 TInt32 tlen = I64LOW(aStart & iBlkMsk);
1382 TInt32 wlen = UMin(I64LOW((iBlkMsk+1) - tlen), aLength);
1384 const TInt64 usrOfst = (aStart - iReqStart);
1385 TPtr8 tgt(&iMinorBuf[tlen], I64LOW(wlen));
1387 if ( (r = iCurrentReq->ReadRemote(&tgt,I64LOW(usrOfst))) != KErrNone)
1389 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT3, this, r );
1394 if (iWtRBM & KWtMinLst)
1396 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:Phys write-last-block-only"));
1397 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_LBO, "Write last block only");
1398 iWtRBM &= ~KWtMinLst;
1399 //Overwrite last block with the new data
1400 const TInt64 medEnds = aStart + aLength;
1401 TInt64 tlen = medEnds & iBlkMsk;
1403 const TInt64 usrOfst = (aStart - iReqStart);
1404 TPtr8 tgt(iCacheBuf, I64LOW(tlen));
1406 if ( (r = iCurrentReq->ReadRemote(&tgt,I64LOW(usrOfst+aLength-tlen))) !=KErrNone)
1408 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT4, this, r );
1413 // no reads required - read data from user buffer and launch write
1414 const TInt64 usrOfst = (aStart - iReqStart);
1415 const TInt64 bufOfst = aStart - iPhysStart; // offset into first sector, not whole buffer
1416 const TInt64 len = UMin(aStart + aLength, iPhysEnd) - iReqCur;
1417 __ASSERT_DEBUG(len > 0, Panic(ELWLength));
1418 __ASSERT_DEBUG(I64HIGH(usrOfst) == 0, Panic(ELWLength));
1420 if (iDoPhysicalAddress)
1422 TPhysAddr physAddr = 0;
1423 TInt physLength = 0;
1424 TUint32 physLen = I64LOW(iPhysEnd - iPhysStart);
1426 if (iWtRBM & KWtMinFst)
1428 #if !defined(__WINS__)
1429 physAddr = Epoc::LinearToPhysical((TLinAddr)iMinorBuf);
1431 physAddr = (TPhysAddr)iMinorBuf;
1433 physLength = iBlkLen;
1434 iBufOfset = I64LOW(iReqStart - iPhysStart);
1435 //iReqCur already set in DoWrite
1436 iFragOfset = iIPCLen = iBlkLen - iBufOfset;
1437 iWtRBM &= ~KWtMinFst;
1441 iFragOfset = I64LOW(usrOfst);
1443 r = PrepareFirstPhysicalFragment(physAddr, physLength, aLength);
1449 iPhysEnd = iPhysStart+physLength;
1451 if ((TUint32)physLength > physLen) physLength = physLen; // more memory in fragment than required!
1452 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_PHYSICAL, "Physical write request" );
1453 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), (TUint8*) physAddr, physLen >> KMMCardHighCapBlockSizeLog2);
1454 iSession->Command().iFlags|= KMMCCmdFlagPhysAddr;
1455 iSession->EnableDoubleBuffering(physLength >> KDiskSectorShift);
1459 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lw:Phys:%d", r));
1461 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT5, this, r );
1464 } // if (iDoPhysicalAddress)
1467 TPtr8 tgt(&iIntBuf[bufOfst], I64LOW(len));
1469 r = ReadDataFromUser(tgt, I64LOW(usrOfst));
1472 if(!iDoDoubleBuffer)
1474 // EPBUSM automatically uses CMD24 instead of CMD25 for single block writes
1475 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_STANDARD, "Standard write request" );
1476 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2));
1481 // When double-buffering, set up the data transfer command to the entire
1482 // request range. and flag the session to enable double-buffering (as well
1483 // as specifying the length of each double-buffered transfer as calculated
1484 // in 'len' above). This is performed only once - the double-buffering
1485 // is subsequently handled within the DoDataTransferCallback function.
1487 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_DB, "Double-buffered write request" );
1488 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW((((iDbEnd + iBlkMsk) & ~iBlkMsk) - iPhysStart) >> KMMCardHighCapBlockSizeLog2));
1489 iSession->EnableDoubleBuffering(I64LOW((len + iBlkMsk) & ~iBlkMsk) >> KDiskSectorShift);
1491 // ...and switch to the 'second' buffer, which will be populated in the
1492 // data transfer callback in parallel with hardware transfer of the first.
1493 iSecondBuffer = ETrue;
1498 //Reliable Write only supported by v4.3+ MMC media
1499 if (iCard->ExtendedCSD().ExtendedCSDRev() >= 3)
1501 // One request, i.e. not end of previous DB request
1502 // 512 Bytes long when sector aligned
1503 if ( ( I64LOW(iPhysEnd - iPhysStart) == iBlkLen) && ((iReqStart & ~iBlkMsk) == iPhysStart) )
1505 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:AtomicWrite"));
1506 iSession->Command().iFlags|= KMMCCmdFlagReliableWrite;
1510 // Engage the data transfer session...
1511 r = EngageAndSetWriteRequest(aMedReq);
1512 } // if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone)
1514 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lw:%d", r));
1516 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT6, this, r );
1520 TInt DMmcMediaDriverFlash::PartitionInfo(TPartitionInfo& anInfo)
1522 // Read the partition information for the media. If the user supplied a password,
1523 // then unlock the card before trying to read the first sector.
1526 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_PARTITIONINFO_ENTRY, this );
1527 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rpi"));
1528 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(ERPIInUse));
1530 iPartitionInfo = &anInfo;
1532 if(iMmcPartitionInfo)
1534 // If this is an embedded device, use the custom formatting function:
1535 TInt r = iMmcPartitionInfo->PartitionInfo(*iPartitionInfo, iSessionEndCallBack);
1537 iHiddenSectors = 0; // Not used for internal media
1540 iMedReq = EMReqEMMCPtnInfo;
1542 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT1, this, r );
1546 // Assume MBR will be present or is not required
1547 iMbrMissing = EFalse;
1549 // If media driver is persistent (see EMediaDriverPersistent),
1550 // the card may have changed since last power down, so reset CID
1551 iSession->SetCard(iCard);
1553 TInt r = LaunchRPIRead();
1555 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rpi:%d", r));
1559 // If the media is locked, we present a default partition entry to the local
1560 // media subsystem, which will be updated when the media is finally unlocked.
1561 r = CreateDefaultPartition();
1564 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT2, this, r );
1568 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT3, this, KErrLocked );
1572 // KErrNone indicates asynchronous completion
1574 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT4, this, r );
1578 TInt DMmcMediaDriverFlash::LaunchRPIUnlock(TLocalDrivePasswordData& aPasswordData)
1580 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_LAUNCHRPIUNLOCK_ENTRY, this );
1581 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lru:%d,%d", iCard->IsReady(), iCard->IsLocked()));
1582 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHRPIUNLOCK_ICARD, "iCard->IsReady=%d; iCard->IsLocked=%d", iCard->IsReady(), iCard->IsLocked());
1583 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
1587 // CMD42 is an adtc, so check state in same way as for write
1588 if ((r = CheckDevice(EMReqTypeUnlockPswd)) == KErrNone)
1590 r = Stack().MMCSocket()->PrepareStore(CardNum(), DLocalDrive::EPasswordUnlock, aPasswordData);
1594 TMediaPassword curPwd;
1596 curPwd = *aPasswordData.iOldPasswd;
1598 TInt curPwdLen = curPwd.Length();
1599 TInt blockLen = 2 + curPwdLen;
1601 TPtr8 pbuf(&iMinorBuf[0], 2, blockLen);
1602 pbuf[0] = 0; // LOCK_UNLOCK = 0; SET_PWD = 0
1603 pbuf[1] = static_cast<TUint8>(curPwdLen);
1604 pbuf.Append(curPwd);
1605 iSession->SetupCIMLockUnlock(blockLen, iMinorBuf);
1607 r = EngageAndSetWriteRequest(EMReqUpdatePtnInfo);
1611 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lru:%d", r));
1612 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHRPIUNLOCK_EXIT, this, r );
1617 TInt DMmcMediaDriverFlash::LaunchRPIRead()
1619 // launch read request on first KDiskSectorSize (512) bytes
1622 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_LAUNCHRPIREAD_ENTRY, this );
1623 __KTRACE_OPT(KPBUSDRV, Kern::Printf((">mmd:lrr")));
1624 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
1626 // the partition information is read before any other area is read from /
1627 // written to, and so does not need to maintain cache coherence. Therefore
1628 // it can safely use the minor buffer.
1631 if ((r = CheckDevice(EMReqTypeNormalRd)) == KErrNone)
1633 iIntBuf = iMinorBuf;
1634 iSession->SetupCIMReadBlock(0, iIntBuf); // aBlocks = 1
1635 r = EngageAndSetReadRequest(EMReqPtnInfo);
1638 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lrr:%d", r));
1639 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHRPIREAD_EXIT, this, r );
1644 TInt DMmcMediaDriverFlash::LaunchRPIErase()
1646 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_LAUNCHRPIERASE_ENTRY, this );
1647 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lre:%d,%d", iCard->IsReady(), iCard->IsLocked()));
1648 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
1652 // CMD42 is an adtc, so check state in same way as for write
1653 if ((r = CheckDevice(EMReqTypeUnlockPswd)) == KErrNone)
1655 if(iCard->IsWriteProtected())
1657 r = KErrAccessDenied;
1661 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:df:EMReqForceErase"));
1662 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHRPIERASE_FORCE_ERASE, "Force erase");
1663 iMinorBuf[0] = KMMCLockUnlockErase;
1664 iSession->SetupCIMLockUnlock(1, iMinorBuf);
1665 r = EngageAndSetWriteRequest(EMReqForceErase);
1669 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lru:%d", r));
1670 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHRPIERASE_EXIT, this, r );
1675 TInt DMmcMediaDriverFlash::DecodePartitionInfo()
1677 // decode partition info that was read into internal buffer
1680 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_ENTRY, this );
1681 TInt partitionCount=iPartitionInfo->iPartitionCount=0;
1682 TInt defaultPartitionNumber=-1;
1683 TMBRPartitionEntry* pe;
1684 const TUint KMBRFirstPartitionOffsetAligned = KMBRFirstPartitionOffset & ~3;
1687 // Read of the first sector successful so check for a Master Boot Record
1688 if (*(TUint16*)(&iIntBuf[KMBRSignatureOffset])!=0xAA55)
1691 __ASSERT_COMPILE(KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry) <= KMBRSignatureOffset);
1693 memmove(&iIntBuf[0], &iIntBuf[2],
1694 KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry));
1697 for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]);
1698 pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++)
1700 if (pe->IsDefaultBootPartition())
1702 SetPartitionEntry(&iPartitionInfo->iEntry[0],pe->iFirstSector,pe->iNumSectors);
1703 defaultPartitionNumber=i;
1709 // Now add any other partitions
1710 for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]);
1711 pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++)
1713 TBool validPartition = ETrue; // assume partition valid
1715 if (defaultPartitionNumber==i)
1721 else if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition() || pe->IsValidExFATPartition())
1723 SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
1724 __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: FAT partition found at sector #%u", pe->iFirstSector));
1725 OstTrace1(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_FS,"FAT partition found at sector #%u", pe->iFirstSector);
1730 validPartition = EFalse;
1733 if (validPartition && partitionCount == 1)
1734 iHiddenSectors = pe->iFirstSector;
1738 // Check the validity of the partition address boundaries
1740 if(partitionCount > 0)
1742 const TInt64 deviceSize = iCard->DeviceSize64();
1743 TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1];
1744 // Check that the card address space boundary is not exceeded by the last partition
1745 // In case of only 1 partition in the media check also it
1746 if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize)
1748 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space"));
1749 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT1, "MBR partition exceeds card memory space" );
1750 // Adjust the partition length to card address boundary
1751 part.iPartitionLen = (deviceSize - part.iPartitionBaseAddr);
1753 // Check that the base address contained valid information
1754 if(part.iPartitionLen <= 0)
1756 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Invalid base address"));
1757 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT2, "Invalid base address" );
1758 // Invalid MBR - assume the boot sector is in the first sector
1759 defaultPartitionNumber =-1;
1763 // More than one partition. Go through all of them
1764 if (partitionCount > 0)
1766 for(i=partitionCount-1; i>0; i--)
1768 const TPartitionEntry& curr = iPartitionInfo->iEntry[i];
1769 TPartitionEntry& prev = iPartitionInfo->iEntry[i-1];
1770 // Check if partitions overlap
1771 if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen))
1773 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Overlapping partitions"));
1774 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT3, "Overlapping partitions" );
1775 // Adjust the partition length to not overlap the next partition
1776 prev.iPartitionLen = (curr.iPartitionBaseAddr - prev.iPartitionBaseAddr);
1778 // Check that the base address contained valid information
1779 if(prev.iPartitionLen <= 0)
1781 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Invalid base address"));
1782 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT4, "Invalid base address" );
1783 // Invalid MBR - assume the boot sector is in the first sector
1784 defaultPartitionNumber=(-1);
1793 if (defaultPartitionNumber==(-1) && partitionCount==0)
1795 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc:PartitionInfo no MBR"));
1796 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_MBRDONE1, "No MBR" );
1797 if (MBRMandatory(iCard))
1799 // If the MBR is missing AND is required, we present a default partition entry to the local
1800 // media subsystem, which will be updated when the media is finally formatted
1801 __KTRACE_OPT(KPBUSDRV, Kern::Printf("MBR mandatory, defining space for MBR + default partition"));
1802 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_MBRDONE2, "MBR mandatory, defining space for MBR + default partition" );
1803 iMbrMissing = ETrue;
1804 TInt r = CreateDefaultPartition();
1807 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_EXIT1, this, r );
1813 // Assume it has no MBR, and the Boot Sector is in the 1st sector
1814 SetPartitionEntry(&iPartitionInfo->iEntry[0],0,I64LOW(iCard->DeviceSize64()>>KDiskSectorShift));
1820 iPartitionInfo->iPartitionCount=partitionCount;
1821 iPartitionInfo->iMediaSizeInBytes=TotalSizeInBytes();
1823 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<Mmc:PartitionInfo (C:%d)",iPartitionInfo->iPartitionCount));
1824 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition1 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[0].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[0].iPartitionLen)));
1825 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition2 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[1].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[1].iPartitionLen)));
1826 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition3 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[2].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[2].iPartitionLen)));
1827 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition4 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[3].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[3].iPartitionLen)));
1828 OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTINFO1, "Partition1 (B:0x%x L:0x%x); Partition2 (B:0x%x L:0x%x)", I64LOW(iPartitionInfo->iEntry[0].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[0].iPartitionLen),I64LOW(iPartitionInfo->iEntry[1].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[1].iPartitionLen));
1829 OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTINFO2, "Partition3 (B:0x%x L:0x%x); Partition4 (B:0x%x L:0x%x)", I64LOW(iPartitionInfo->iEntry[2].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[2].iPartitionLen),I64LOW(iPartitionInfo->iEntry[3].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[3].iPartitionLen));
1832 TMBRPartitionEntry cPe;
1833 if(GetDefaultPartitionInfo(cPe) == KErrNone)
1835 pe = (TMBRPartitionEntry*)(&iIntBuf[0]);
1837 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------"));
1838 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- Partition Entry Validation/Comparison --"));
1839 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------"));
1840 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iX86BootIndicator [%02x:%02x] %c -", pe->iX86BootIndicator, cPe.iX86BootIndicator, pe->iX86BootIndicator == cPe.iX86BootIndicator ? ' ' : 'X'));
1841 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartHead [%02x:%02x] %c -", pe->iStartHead, cPe.iStartHead, pe->iStartHead == cPe.iStartHead ? ' ' : 'X'));
1842 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartSector [%02x:%02x] %c -", pe->iStartSector, cPe.iStartSector, pe->iStartSector == cPe.iStartSector ? ' ' : 'X'));
1843 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartCylinder [%02x:%02x] %c -", pe->iStartCylinder, cPe.iStartCylinder, pe->iStartCylinder == cPe.iStartCylinder ? ' ' : 'X'));
1844 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iPartitionType [%02x:%02x] %c -", pe->iPartitionType, cPe.iPartitionType, pe->iPartitionType == cPe.iPartitionType ? ' ' : 'X'));
1845 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndHead [%02x:%02x] %c -", pe->iEndHead, cPe.iEndHead, pe->iEndHead == cPe.iEndHead ? ' ' : 'X'));
1846 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndSector [%02x:%02x] %c -", pe->iEndSector, cPe.iEndSector, pe->iEndSector == cPe.iEndSector ? ' ' : 'X'));
1847 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndCylinder [%02x:%02x] %c -", pe->iEndCylinder, cPe.iEndCylinder, pe->iEndCylinder == cPe.iEndCylinder ? ' ' : 'X'));
1848 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iFirstSector [%08x:%08x] %c -", pe->iFirstSector, cPe.iFirstSector, pe->iFirstSector == cPe.iFirstSector ? ' ' : 'X'));
1849 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iNumSectors [%08x:%08x] %c -", pe->iNumSectors, cPe.iNumSectors, pe->iNumSectors == cPe.iNumSectors ? ' ' : 'X'));
1850 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------"));
1854 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_EXIT2, this, KErrNone );
1859 TInt DMmcMediaDriverFlash::WritePartitionInfo()
1861 Write the default partition table to freshly formatted media
1862 @return Standard Symbian OS Error Code
1865 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_ENTRY, this );
1866 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:wpi"));
1867 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
1869 TMBRPartitionEntry partitionEntry;
1870 TInt err = GetDefaultPartitionInfo(partitionEntry);
1873 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:MBR/Partition Table"));
1874 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Boot ID : %02xh", partitionEntry.iX86BootIndicator));
1875 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Head : %02xh", partitionEntry.iStartHead));
1876 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Sector : %02xh", partitionEntry.iStartSector));
1877 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Cyclinder : %02xh", partitionEntry.iStartCylinder));
1878 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" System ID : %02xh", partitionEntry.iPartitionType));
1879 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Head : %02xh", partitionEntry.iEndHead));
1880 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Sector : %02xh", partitionEntry.iEndSector));
1881 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Cyclinder : %02xh", partitionEntry.iEndCylinder));
1882 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Relative Sector : %08xh", partitionEntry.iFirstSector));
1883 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Number of Sectors: %08xh", partitionEntry.iNumSectors));
1884 OstTraceExt5(TRACE_MMCDEBUG, DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_PARTINFO1, "Boot ID=0x%02x; Start Head=0x%02x; Start Sector=0x%02x; Start Cyclinder=0x%02x; System ID=0x%02x", (TUint) partitionEntry.iX86BootIndicator, (TUint) partitionEntry.iStartHead, (TUint) partitionEntry.iStartSector, (TUint) partitionEntry.iStartCylinder, (TUint) partitionEntry.iPartitionType);
1885 OstTraceExt5(TRACE_MMCDEBUG, DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_PARTINFO2, "End Head=0x%02x; End Sector=0x%02x; End Cyclinder=0x%02x; Relative Sector=0x%08x; Number of Sectors=0x%08x", (TUint) partitionEntry.iEndHead, (TUint) partitionEntry.iEndSector, (TUint) partitionEntry.iEndCylinder, (TUint) partitionEntry.iFirstSector, (TUint) partitionEntry.iNumSectors);
1887 // Clear all other partition entries and align the partition info into the minor buffer for writing...
1889 memclr(iMinorBuf, KDiskSectorSize);
1890 memcpy(&iMinorBuf[KMBRFirstPartitionEntry], &partitionEntry, sizeof(TMBRPartitionEntry));
1892 *(TUint16*)(&iMinorBuf[KMBRSignatureOffset]) = 0xAA55;
1894 iSession->SetupCIMWriteBlock(0, iMinorBuf);
1897 // Write the partition table and engage the read to validate and complete the mount process
1899 iMbrMissing = EFalse;
1900 iCreateMbr = EFalse;
1901 err = EngageAndSetWriteRequest(EMReqUpdatePtnInfo);
1904 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:wpi:%d", err));
1906 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_EXIT, this, err );
1911 TInt DMmcMediaDriverFlash::CreateDefaultPartition()
1913 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CREATEDEFAULTPARTITION_ENTRY, this );
1914 TMBRPartitionEntry defPartition;
1915 TInt r = GetDefaultPartitionInfo(defPartition);
1918 SetPartitionEntry(&iPartitionInfo->iEntry[0], defPartition.iFirstSector, defPartition.iNumSectors);
1919 iHiddenSectors = defPartition.iFirstSector;
1920 iPartitionInfo->iPartitionCount = 1;
1921 iPartitionInfo->iMediaSizeInBytes = TotalSizeInBytes();
1923 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CREATEDEFAULTPARTITION_EXIT, this, r );
1927 TInt DMmcMediaDriverFlash::GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry)
1929 Calculates the default patition information for an specific card.
1930 @param aPartitionEntry The TMBRPartitionEntry to be filled in with the format parameters
1931 @return Standard Symbian OS Error Code
1934 memclr(&aPartitionEntry, sizeof(TMBRPartitionEntry));
1935 TUint16 reservedSectors; // Not used
1936 TInt r = GetMediaDefaultPartitionInfo(aPartitionEntry, reservedSectors, iCard);
1941 void DMmcMediaDriverFlash::SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors)
1943 // auxiliary static function to record partition information in TPartitionEntry object
1946 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_SETPARTITIONENTRY_ENTRY );
1947 aEntry->iPartitionBaseAddr=aFirstSector;
1948 aEntry->iPartitionBaseAddr<<=KDiskSectorShift;
1949 aEntry->iPartitionLen=aNumSectors;
1950 aEntry->iPartitionLen<<=KDiskSectorShift;
1951 aEntry->iPartitionType=KPartitionTypeFAT12;
1952 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_SETPARTITIONENTRY_EXIT );
1955 TInt DMmcMediaDriverFlash::DoPasswordOp()
1957 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPASSWORDOP_ENTRY, this );
1958 // Reconstruct password data structure in our address space
1959 TLocalDrivePasswordData clientData;
1960 TInt r = iCurrentReq->ReadRemoteRaw(&clientData, sizeof(TLocalDrivePasswordData));
1962 TMediaPassword oldPassword;
1964 r = iCurrentReq->ReadRemote(clientData.iOldPasswd, &oldPassword);
1966 TMediaPassword newPassword;
1968 r = iCurrentReq->ReadRemote(clientData.iNewPasswd, &newPassword);
1970 TLocalDrivePasswordData passData(oldPassword, newPassword, clientData.iStorePasswd);
1974 TInt id=iCurrentReq->Id();
1977 case DLocalDrive::EPasswordUnlock:
1978 r = LaunchRPIUnlock(passData);
1979 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rpi:%d", r));
1981 case DLocalDrive::EPasswordLock:
1982 case DLocalDrive::EPasswordClear:
1983 PasswordControl(id, passData);
1988 // This will complete the request in the event of an error
1990 PartitionInfoComplete(r);
1992 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOPASSWORDOP_EXIT, this, KErrNone );
1993 return KErrNone; // ensures to indicate asynchronoous completion
1996 void DMmcMediaDriverFlash::PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData)
1998 // Change a card's password, or clear the pasword from a locked card. The card
1999 // must be unlocked for this function. A locked card is unlocked when it is mounted,
2000 // to read the partition information. This is done from ReadPartitionInfo() and
2001 // LaunchRPIUnlock().
2004 OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_PASSWORDCONTROL_ENTRY ,"DMmcMediaDriverFlash::PasswordControl;aFunc=%d;this=%x", aFunc, (TUint) this);
2005 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:pc:%d", (TInt) aFunc));
2006 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EPCInUse));
2007 __ASSERT_DEBUG(aFunc == DLocalDrive::EPasswordLock || aFunc == DLocalDrive::EPasswordClear, Panic(EPCFunc));
2008 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
2012 if ((r = CheckDevice(EMReqTypeChangePswd)) == KErrNone)
2014 // check if the current password is correct here. (This makes the
2015 // clear operation redundant only if the password is stored and it
2016 // is wrong.) Complete with same value as DoSessionEndDfc() would.
2018 TMediaPassword curPwd;
2020 curPwd = *aData.iOldPasswd;
2021 TInt curPwdLen = curPwd.Length();
2024 if (!(iCard->iFlags & KMMCardIsLockable))
2025 r = KErrNotSupported;
2026 else if (Stack().PasswordStore()->IsMappingIncorrect(iCard->CID(), curPwd))
2027 r = KErrAccessDenied;
2030 if ((r = Stack().MMCSocket()->PrepareStore(CardNum(), aFunc, aData/*, aThread*/)) == KErrNone)
2034 case DLocalDrive::EPasswordLock:
2036 TMediaPassword newPwd;
2037 newPwd = *aData.iNewPasswd;
2038 TInt newPwdLen = newPwd.Length();
2039 blockLen = 1 + 1 + curPwdLen + newPwdLen;
2042 TUint16 env_Var[]=L"_EPOC_PWD_LEN";
2044 env_Val[0]=(TUint16)(curPwdLen+1);
2045 env_Val[1]=0;//make a null terminated string
2046 r=SetEnvironmentVariable(env_Var,&env_Val[0]);
2047 __ASSERT_DEBUG(r!=0, Panic(EPCFunc));
2051 TPtr8 pbuf(&iMinorBuf[0], 2, blockLen);
2052 pbuf[0] = KMMCLockUnlockSetPwd; // LOCK_UNLOCK = 0, SET_PWD = 1
2053 pbuf[1] = static_cast<TUint8>(curPwdLen + newPwdLen);
2054 pbuf.Append(curPwd);
2055 pbuf.Append(newPwd);
2059 case DLocalDrive::EPasswordClear:
2061 blockLen = 1 + 1 + curPwdLen;
2063 TPtr8 pbuf(&iMinorBuf[0], 2, blockLen);
2064 pbuf[0] = KMMCLockUnlockClrPwd; // LOCK_UNLOCK = dc, CLR_PWD = 1
2065 pbuf[1] = static_cast<TUint8>(curPwdLen);
2066 pbuf.Append(curPwd);
2071 // DLocalDrive::EPasswordUnlock is not handled. This avoids warnings for unused
2072 // case, and uninitialized variable.
2077 iSession->SetupCIMLockUnlock(blockLen, iMinorBuf);
2078 r = EngageAndSetWriteRequest(EMReqPswdCtrl);
2079 } // if ((r = Stack().PrepareStore(CardNum(), aFunc, aData, aThread)) == KErrNone)
2080 } // else (Stack().IsMappingIncorrect(iCard->CID(), curPwd))
2081 } // (r = CheckDevice(EMReqTypeChangePswd)) == KErrNone
2083 // complete immediately if error occured
2087 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:pc:%d", r));
2088 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_PASSWORDCONTROL_EXIT, this );
2092 // ---- device status, callback DFC ----
2094 TInt DMmcMediaDriverFlash::CheckDevice(TMediaReqType aReqType)
2096 // Check the device before initiating a command
2099 OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_CHECKDEVICE_ENTRY, "DMmcMediaDriverFlash::CheckDevice;aReqType=%d;this=%x", (TInt) aReqType, (TUint) this);
2100 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:cd:%d",aReqType));
2104 if (!iCard->IsReady())
2107 // The card must be locked if attempting to unlock during RPI, and
2108 // unlocked at all other times.
2109 else if (aReqType!=EMReqTypeUnlockPswd && iCard->IsLocked())
2111 // Don't perform Password setting for WriteProtected cards,
2112 // unable to recover (ForcedErase) if password lost.
2113 else if (aReqType==EMReqTypeChangePswd)
2115 if (iCard->MediaType()==EMultiMediaROM)
2120 else if (iMbrMissing && aReqType==EMReqTypeNormalRd)
2123 #if !defined(__WINS__)
2124 // Don't perform write/password operations when the battery is low
2125 // else if (aReqType!=EMReqTypeNormalRd && Hal::MainBatteryStatus()<ELow && !Hal::ExternalPowerPresent())
2128 // Don't perform write operations when the mechanical write protect switch is set
2129 else if (aReqType==EMReqTypeNormalWr && iCard->IsWriteProtected())
2131 // Don't perform write/format operations on MMC ROM cards
2132 else if (iMediaType==EMultiMediaROM && aReqType == EMReqTypeNormalWr)
2135 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:cd:%d", r));
2136 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CHECKDEVICE_EXIT, this, r );
2140 void DMmcMediaDriverFlash::SessionEndCallBack(TAny* aMediaDriver)
2142 // called by EPBUS when a single session has finished. Queues DFC to launch
2143 // next session or to complete client request.
2146 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_SESSIONENDCALLBACK_ENTRY );
2147 DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver);
2148 __ASSERT_DEBUG(! md.iSessionEndDfc.Queued(), Panic(ESECBQueued));
2149 md.iSessionEndDfc.Enque();
2150 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_SESSIONENDCALLBACK_EXIT );
2154 void DMmcMediaDriverFlash::SessionEndDfc(TAny* aMediaDriver)
2156 static_cast<DMmcMediaDriverFlash*>(aMediaDriver)->DoSessionEndDfc();
2160 void DMmcMediaDriverFlash::DoSessionEndDfc()
2162 // launch next session or complete client request
2165 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_ENTRY, this );
2166 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dsed:%d", CurrentRequest()));
2167 OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_REQUEST, "Current Request=%d", CurrentRequest());
2173 // Abort if writing or formatting and power has gone down
2174 if (!Kern::PowerGood() && CurrentRequest()!=EMReqRead)
2176 // Return KErrNotReady if we have has a deferred media change
2177 if (!iCard->IsReady())
2179 // if stack has powered down session pointer will be NULL
2180 if (iSession == NULL)
2183 TBool complete = ETrue;
2187 r = iSession->EpocErrorCode();
2189 switch (CurrentRequest())
2193 if (r != KErrNone) // abort if MMC error
2199 // This is the end of a double-buffered transfer.
2200 // - Now we have two buffers to copy back to the user...
2202 TUint8* bufPtr = iIntBuf + (iSecondBuffer ? (iMaxBufSize >> 1) : 0);
2203 if((r = WriteDataToUser(bufPtr)) == KErrNone)
2205 MarkBlocks(iReqCur, iPhysEnd, CchMemToIdx(bufPtr));
2210 bufPtr = iIntBuf + (iSecondBuffer ? 0 : (iMaxBufSize >> 1));
2211 if((r = WriteDataToUser(bufPtr)) == KErrNone)
2213 MarkBlocks(iReqCur, (iPhysEnd + iBlkMsk) & ~iBlkMsk, CchMemToIdx(bufPtr));
2216 iDoDoubleBuffer = EFalse;
2218 else if (iDoPhysicalAddress)
2220 if (iRdROB & KIPCWrite)
2222 // partial end point
2223 TInt len = I64LOW(iReqEnd & iBlkMsk);
2224 const TInt ofset = I64LOW(iPhysEnd - iBlkLen - iReqStart);
2226 TPtrC8 extrView(iIntBuf, len);
2227 r = iCurrentReq->WriteRemote(&extrView,ofset);
2231 iFragOfset = iIPCLen = iBufOfset = 0;
2232 iReqCur = iPhysEnd = iReqEnd;
2233 iDoPhysicalAddress = EFalse;
2237 r = WriteDataToUser(&iIntBuf[I64LOW(iReqCur - iPhysStart)]);
2243 // if there is more information to read for the user then engage another session
2244 if ((iReqCur = iPhysEnd) < iReqEnd)
2246 TBool allDone = EFalse;
2247 if ( ((r = ReadDataUntilCacheExhausted(&allDone)) == KErrNone) && !allDone)
2249 iPhysStart = iReqCur & ~iBlkMsk;
2250 TUint32 length = I64LOW(iReqEnd - iReqCur);
2252 if ( (iReqEnd - iPhysStart) > iMaxBufSize && iSocket->SupportsDoubleBuffering() && !iReadToEndOfCard)
2255 r = LaunchRead(iReqCur, length);
2266 if (r != KErrNone) // abort if MMC error
2274 iDoDoubleBuffer = EFalse;
2275 iDoPhysicalAddress = EFalse;
2277 iFragOfset = iIPCLen = iBufOfset = 0;
2279 // clear current RBM flag
2282 if (iWtRBM & KWtRBMFst)
2284 iWtRBM &= ~KWtRBMFst;
2286 else if (iWtRBM & KWtRBMLst)
2288 iWtRBM &= ~KWtRBMLst;
2292 // advance media position if just finished write, as opposed to read-before-modify
2293 if (iReqCur < iReqEnd)
2295 if ((r = LaunchWrite(iReqCur, I64LOW(iReqEnd - iReqCur), EMReqWrite)) == KErrNone)
2300 complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse;
2307 if (r != KErrNone) // abort if MMC error
2310 if ((iEraseUnitMsk == KMaxTUint64) || // no erase unit defined (Erase Class Commands not supported) ?
2311 (iPhysEnd == iReqEnd) || // finshed already ?
2312 ((iPhysStart & iEraseUnitMsk) == 0 && (iPhysEnd & iEraseUnitMsk) == 0))
2318 // Formating to a mis-aligned boundary, so we can't make best use of
2319 // multiple erase blocks. We shall simply erase up to the next block
2320 // boundary, and return the adjustment info to the file system
2321 r = I64LOW(iPhysEnd - iPhysStart);
2327 // advance media position if just finished write, as opposed to read-before-modify
2328 if (iReqCur < iReqEnd)
2330 if ((r = LaunchFormat(iReqCur, I64LOW(iReqEnd - iReqCur))) == KErrNone)
2335 // if format finished, write an MBR if required
2336 // Always write an MBR if it's an SD card
2337 else if (iCreateMbr)
2339 // Finished Format, so write the MBR/default partition table if required
2340 r = WritePartitionInfo();
2341 complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse;
2349 r = DecodePartitionInfo(); // set up iPartitionInfo
2351 PartitionInfoComplete(r == KErrNone?KErrNone:KErrNotReady);
2354 case EMReqEMMCPtnInfo:
2355 iMedReq = EMReqIdle;
2356 // For now do nothing..
2359 case EMReqUpdatePtnInfo:
2363 if (r == KErrLocked)
2364 r = KErrAccessDenied;
2367 case EMReqForceErase:
2371 // Finished Forced Erase , so write the default partition table...
2372 r = WritePartitionInfo();
2375 complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse;
2378 case EMReqWritePasswordData:
2380 // WritePasswordData also kicks off an auto-unlock session to ensure that
2381 // any locked cards that have passwords in the password store are immediately
2382 // available. We can safely ignore any errors returned at this stage, as the
2383 // password store will have been successfully updated (in locmedia.cpp), even
2384 // if the card is unable to accept the password.
2390 // request has been completed already (e.g. due to a power down)
2395 __ASSERT_DEBUG(EFalse, Panic(EDSEDRequest));
2400 // r != KErrNone => complete
2401 __ASSERT_DEBUG(!(r != KErrNone) || complete, Panic(EDSEDNotErrComplete));
2408 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mdf:dsed:cmp:%d", r));
2409 OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_COMPLETE, "Complete request; retval=%d", r);
2414 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mdf:dsed:ncmp"));
2415 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_NOT_COMPLETE, "Request not complete");
2417 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_EXIT, this );
2420 void DMmcMediaDriverFlash::DataTransferCallBack(TAny* aMediaDriver)
2422 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACK_ENTRY );
2423 DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver);
2424 __ASSERT_DEBUG(! md.iDataTransferCallBackDfc.Queued(), Panic(EDBCBQueued));
2425 md.iDataTransferCallBackDfc.Enque();
2426 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACK_EXIT );
2429 void DMmcMediaDriverFlash::DataTransferCallBackDfc(TAny* aMediaDriver)
2431 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACKDFC_ENTRY );
2432 DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver);
2434 if (md.iDoPhysicalAddress)
2436 if(md.CurrentRequest() == EMReqWrite)
2438 md.DoPhysWriteDataTransferCallBack();
2442 md.DoPhysReadDataTransferCallBack();
2447 if(md.CurrentRequest() == EMReqWrite)
2449 md.DoWriteDataTransferCallBack();
2453 md.DoReadDataTransferCallBack();
2456 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACKDFC_EXIT );
2459 void DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()
2461 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_ENTRY, this );
2462 __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()"));
2464 TInt err = KErrNone;
2466 if ( (iRdROB & KIPCSetup) || ((iReqEnd - iPhysEnd) < iBlkLen) )
2468 //IPC to be setup, or partial end block read
2469 iRdROB &= ~KIPCSetup;
2471 if ((iReqEnd - iPhysEnd) < iBlkLen)
2473 iIntBuf = iCacheBuf;
2477 TPtr8 tgt(iMinorBuf, iBlkLen);
2478 err = ReadDataFromUser(tgt, I64LOW(iPhysEnd-iReqStart));
2479 iIntBuf = iMinorBuf;
2483 iPhysEnd += iBlkLen;
2487 #if !defined(__WINS__)
2488 iSession->MoreDataAvailable( (TInt)(iBlkLen >> KDiskSectorShift), (TUint8*)Epoc::LinearToPhysical((TLinAddr) iIntBuf), err);
2490 iSession->MoreDataAvailable( (TInt)(iBlkLen >> KDiskSectorShift), iIntBuf, err);
2492 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--iDoPhysicalAddress(KIPCSetup)"));
2493 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_EXIT1, this );
2497 PrepareNextPhysicalFragment();
2499 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()"));
2500 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_EXIT2, this );
2504 void DMmcMediaDriverFlash::DoPhysReadDataTransferCallBack()
2506 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_ENTRY, this );
2507 __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoPhysReadTransferCallBack()"));
2509 TInt err = KErrNone;
2511 if ((iRdROB & KIPCWrite) && !iSecondBuffer)
2513 // an IPC transfer completed
2514 iRdROB &= ~KIPCWrite;
2517 // First transfer is an IPC,
2518 // Corner-case - transfer is most likely IPC-DMA-IPC,
2519 // because write cannot occur until after the first 2 iterations it is possible to arrive here with both IPCSetup & IPCWrite Set.
2520 // need to use iIPCNxtLen instead
2521 TPtrC8 extrView(&iIntBuf[iBufOfset], iNxtIPCLen);
2522 err = iCurrentReq->WriteRemote(&extrView,I64LOW(iReqCur - iReqStart));
2523 iNxtIPCLen = iBufOfset = 0;
2527 TPtrC8 extrView(&iIntBuf[iBufOfset], iIPCLen);
2528 err = iCurrentReq->WriteRemote(&extrView,I64LOW(iReqCur - iReqStart));
2529 iIPCLen = iBufOfset = 0;
2533 if ( (iRdROB & KIPCSetup) || ((iReqEnd - iPhysEnd) < iBlkLen) )
2535 // IPC to be setup, or partial end block read.
2536 iRdROB &= ~KIPCSetup;
2537 iRdROB |= KIPCWrite;
2539 iIntBuf = ReserveReadBlocks(iPhysEnd,(iPhysEnd+iBlkLen), &iIPCLen);
2542 iPhysEnd += iIPCLen;
2544 #if !defined(__WINS__)
2545 iSession->MoreDataAvailable( (TInt)(iIPCLen >> KDiskSectorShift), (TUint8*)Epoc::LinearToPhysical((TLinAddr) iIntBuf), err);
2547 iSession->MoreDataAvailable( (TInt)(iIPCLen >> KDiskSectorShift), iIntBuf, err);
2549 iSecondBuffer = ETrue;
2550 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--iDoPhysicalAddress(KIPCWrite)"));
2551 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_EXIT1, this );
2555 PrepareNextPhysicalFragment();
2557 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoPhysReadTransferCallBack()"));
2558 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_EXIT2, this );
2561 void DMmcMediaDriverFlash::DoWriteDataTransferCallBack()
2563 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOWRITEDATATRANSFERCALLBACK_ENTRY, this );
2564 __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoWriteDataTransferCallBack()"));
2566 TInt err = KErrNone;
2568 // Advance current request progress...
2571 const TUint32 doubleBufferSize = iMaxBufSize >> 1;
2573 TInt64 length = iDbEnd - iReqCur;
2574 TInt64 medEnd = UMin(iReqCur + doubleBufferSize, iReqCur + length);
2576 iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk;
2577 TInt64 len = UMin(iDbEnd, iPhysEnd) - iReqCur;
2579 if(len > doubleBufferSize)
2581 // Adjust for maximum size of double-buffering
2582 len = doubleBufferSize;
2585 __ASSERT_DEBUG(len > 0, Panic(EDBLength));
2586 __ASSERT_DEBUG(I64HIGH((len + (KDiskSectorSize-1)) >> KDiskSectorShift) == 0, Panic(EDBLengthTooBig));
2588 TUint32 numBlocks = I64LOW((len + (KDiskSectorSize-1)) >> KDiskSectorShift);
2590 const TInt64 usrOfst = (iReqCur - iReqStart);
2592 __ASSERT_DEBUG(I64HIGH(usrOfst) == 0, Panic(EDBOffsetTooBig));
2594 // Setup the next buffer pointer and switch buffers...
2595 TUint8* bufPtr = iIntBuf + (iSecondBuffer ? doubleBufferSize : 0);
2596 TPtr8 tgt(bufPtr, I64LOW(len));
2597 iSecondBuffer = iSecondBuffer ? (TBool)EFalse : (TBool)ETrue;
2599 if(iDoLastRMW && length < doubleBufferSize)
2602 // This is the last transfer, and RMW is required. The result of the read exists
2603 // in iMinorBuf, so copy the non-modified section of the block to the active buffer.
2605 memcpy(&bufPtr[(numBlocks-1) << KDiskSectorShift], iMinorBuf, KDiskSectorSize);
2608 if(I64LOW(iDbEnd - iReqCur) <= iMaxBufSize)
2611 // This is the last transfer (with or without RMW)
2612 // - Mark the last blocks as active in the buffer cache.
2614 MarkBlocks(iReqCur, iPhysEnd, CchMemToIdx(bufPtr));
2618 // Read the requested data from the remote thread...
2620 err = ReadDataFromUser(tgt, I64LOW(usrOfst));
2623 // ...and signal that data is available to the PSL.
2625 iSession->MoreDataAvailable(numBlocks, bufPtr, err);
2627 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoWriteDataTransferCallBack()"));
2628 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOWRITEDATATRANSFERCALLBACK_EXIT, this );
2632 void DMmcMediaDriverFlash::DoReadDataTransferCallBack()
2634 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_ENTRY, this );
2635 __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoReadTransferCallBack()"));
2637 TInt err = KErrNone;
2639 const TUint32 doubleBufferSize = iMaxBufSize >> 1;
2641 TUint32 bufOfst = 0;
2643 if((iReqCur & ~iBlkMsk) == iPhysStart)
2648 // If this is the first callback, don't copy data as it's not available yet
2649 // - just drop through to set up the next buffer.
2651 TUint32 numBlocks = I64LOW((doubleBufferSize + (KDiskSectorSize-1)) >> KDiskSectorShift);
2652 TUint8* bufPtr = iIntBuf + doubleBufferSize;
2654 iSecondBuffer = EFalse;
2656 iSession->MoreDataAvailable(numBlocks, bufPtr, KErrNone);
2657 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_EXIT1, this );
2663 // If this is the second callback we're ready to copy
2664 // back to the client - data may be mis-aligned in the first
2665 // instance, but all subsequent data will be aligned...
2667 bufOfst = I64LOW(iReqCur - iPhysStart);
2671 // ...otherwise, write the previous buffer contents to the user
2672 TUint8* bufPtr = iIntBuf + (iSecondBuffer ? doubleBufferSize : 0);
2674 err = WriteDataToUser(bufPtr + bufOfst);
2676 // Advance current request progress...
2679 TInt64 medEnd = UMin(iReqCur + doubleBufferSize, iDbEnd);
2681 iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk;
2683 // Current buffer is one step ahead of the current request progress...
2684 TInt64 len = UMin((iDbEnd - iPhysEnd + iBlkMsk) & ~iBlkMsk, TInt64(doubleBufferSize));
2686 __ASSERT_DEBUG(len == 0 || (I64HIGH((len + (KDiskSectorSize-1)) >> KDiskSectorShift) == 0), Panic(EDBLengthTooBig));
2688 TUint32 numBlocks = I64LOW((len + (KDiskSectorSize-1)) >> KDiskSectorShift);
2691 // ...switch buffers and signal that data is available to the PSL.
2693 iSecondBuffer = iSecondBuffer ? (TBool)EFalse : (TBool)ETrue;
2695 iSession->MoreDataAvailable(numBlocks, bufPtr, err);
2697 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoDataTransferCallBack()"));
2698 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_EXIT2, this );
2702 // ---- request management ----
2705 TInt DMmcMediaDriverFlash::EngageAndSetReadRequest(DMmcMediaDriverFlash::TMediaRequest aRequest)
2707 OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETREADREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetReadRequest;aRequest=%d;this=%x", (TInt) aRequest, (TUint) this);
2708 TInt r = EngageAndSetRequest(aRequest, iReadCurrentInMilliAmps);
2709 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETREADREQUEST_EXIT, this, r );
2714 TInt DMmcMediaDriverFlash::EngageAndSetWriteRequest(DMmcMediaDriverFlash::TMediaRequest aRequest)
2716 OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETWRITEREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetReadRequest;aRequest=%d;this=%x", (TInt) aRequest, (TUint) this);
2717 TInt r = EngageAndSetRequest(aRequest, iWriteCurrentInMilliAmps);
2718 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETWRITEREQUEST_EXIT, this, r );
2723 TInt DMmcMediaDriverFlash::EngageAndSetRequest(DMmcMediaDriverFlash::TMediaRequest aRequest, TInt aCurrent)
2725 // In WINS, all of the processing, including the callbacks, is done when Engage() is called,
2726 // so the request value must be set up in advanced. Both the request and the current are
2727 // cleared in the corresponding call to CompleteRequest().
2730 OstTraceExt3(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetRequest;aRequest=%d;aCurrent=%d;this=%x", (TInt) aRequest, aCurrent, (TUint) this);
2731 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
2734 SetCurrentConsumption(aCurrent);
2736 TInt r = InCritical();
2739 r = iSession->Engage();
2744 if (!Kern::PowerGood())
2745 r=KErrAbort; // If emergency power down - return abort rather than anything else.
2746 if (!iCard->IsReady())
2747 r=KErrNotReady; // If media change - return not ready rather than anything else.
2751 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETREQUEST_EXIT, this, r );
2756 void DMmcMediaDriverFlash::CompleteRequest(TInt aReason)
2758 // completes the specified request
2761 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_COMPLETEREQUEST_ENTRY, this );
2762 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:cr0x%08x,%d", iCurrentReq, aReason));
2764 iMedReq = EMReqIdle;
2765 SetCurrentConsumption(KIdleCurrentInMilliAmps);
2767 TLocDrvRequest* pR=iCurrentReq;
2770 #ifdef __DEMAND_PAGING__
2771 #if defined(__TEST_PAGING_MEDIA_DRIVER__)
2772 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Complete req Id(%d) with(%d)", pR->Id(), aReason));
2773 #endif // __TEST_PAGING_MEDIA_DRIVER__
2774 #endif // __DEMAND_PAGING__
2776 DMediaDriver::Complete(*pR,aReason);
2778 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_COMPLETEREQUEST_EXIT, this );
2781 TInt DMmcMediaDriverFlash::Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo)
2783 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CAPS_ENTRY, this );
2784 // Fill buffer with current media caps.
2785 aInfo.iType = EMediaHardDisk;
2786 aInfo.iConnectionBusType = EConnectionBusInternal;
2787 aInfo.iDriveAtt = KDriveAttLocal;
2788 aInfo.iMediaAtt = KMediaAttFormattable;
2790 if(iCard->iFlags & KMMCardIsLockable)
2791 aInfo.iMediaAtt |= KMediaAttLockable;
2793 if (iCard->HasPassword())
2794 aInfo.iMediaAtt |= KMediaAttHasPassword;
2795 if (iCard->IsWriteProtected())
2796 aInfo.iMediaAtt |= KMediaAttWriteProtected;
2797 if (iCard->IsLocked())
2798 aInfo.iMediaAtt |= KMediaAttLocked;
2800 aInfo.iFileSystemId = KDriveFileSysFAT;
2802 // Format is performed in multiples of the erase sector (or multiple block) size
2803 aInfo.iMaxBytesPerFormat = iEraseInfo.iPreferredEraseUnitSize;
2805 if ((!iInternalSlot) && (GetCardFormatInfo(iCard,aInfo.iFormatInfo) == KErrNone))
2807 TUint16 reservedSectors;
2808 TMBRPartitionEntry dummy; // Not used here
2809 const TInt r = GetMediaDefaultPartitionInfo(dummy, reservedSectors, iCard);
2812 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CAPS_EXIT1, this, r );
2816 aInfo.iFormatInfo.iReservedSectors = reservedSectors;
2817 aInfo.iExtraInfo = ETrue;
2820 // Set serial number to CID
2821 __ASSERT_DEBUG(KMMCCIDLength<=KMaxSerialNumLength, Kern::PanicCurrentThread(_L("Mmc"), KErrOverflow));
2822 aInfo.iSerialNumLength = KMMCCIDLength;
2823 for (TUint i=0; i<KMMCCIDLength; i++)
2824 aInfo.iSerialNum[i] = iCard->CID().At(i);
2826 // Get block size & erase block size to allow the file system to align first usable cluster correctly
2827 aInfo.iBlockSize = BlockSize(iCard);
2828 aInfo.iEraseBlockSize = EraseBlockSize(iCard);
2830 #if defined(__DEMAND_PAGING__)
2831 // If the stack has flagged this as a demand-paging device, then it is assumed that it is internal
2832 // and (optionally) write protected.
2833 if(aDrive.iPrimaryMedia->iPagingMedia)
2835 aInfo.iMediaAtt|= KMediaAttPageable;
2836 if (iDemandPagingInfo.iWriteProtected)
2838 aInfo.iMediaAtt|= KMediaAttWriteProtected;
2839 aInfo.iMediaAtt&= ~KMediaAttFormattable;
2843 // code paging enabled on this drive ?
2844 if(aDrive.iPagingDrv)
2846 aInfo.iDriveAtt|= KDriveAttPageable;
2853 aInfo.iDriveAtt|= KDriveAttInternal;
2857 aInfo.iDriveAtt|= KDriveAttRemovable;
2861 if (iMmcPartitionInfo)
2863 TLocalDriveCapsV6Buf CapsInfo = aInfo;
2864 iMmcPartitionInfo->PartitionCaps(aDrive,CapsInfo);
2869 if (iMediaType==EMultiMediaROM)
2871 aInfo.iMediaAtt|= KMediaAttWriteProtected;
2872 aInfo.iMediaAtt&= ~KMediaAttFormattable;
2875 // Must return KErrCompletion to indicate that this
2876 // is a synchronous version of the function
2877 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CAPS_EXIT2, this, KErrCompletion );
2878 return KErrCompletion;
2884 TInt DMmcMediaDriverFlash::ReadDataUntilCacheExhausted(TBool* aAllDone)
2886 // scans the cache for blocks corresponding to the range iReqCur to iReqEnd and
2887 // writes them to user memory. Starts at iReqCur & ~iBlkMsk and looks for blocks
2888 // at sequential media positions. Completes when a block is not available, even
2889 // if a following block is available in the cache. *aAllDone is undefined if the
2890 // return value is not KErrNone.
2892 // This function is linear in the number of blocks in the cache.
2895 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED_ENTRY, this );
2896 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rdc:%x,%x", iReqCur, iReqEnd));
2897 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED, "iReqCur=0x%x; iReqEnd=0x%x", (TUint) iReqCur, (TUint) iReqEnd );
2899 if ( iCurrentReq->IsPhysicalAddress()
2900 #if defined(__DEMAND_PAGING__) && !defined(__WINS__)
2901 || DMediaPagingDevice::PageInRequest(*iCurrentReq)
2902 #endif //DEMAND_PAGING
2906 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED_EXIT1, this, KErrNone );
2910 TInt64 physStart = iReqCur & ~iBlkMsk;
2911 TInt64 physEnd = Min(physStart + iMaxBufSize, (iReqEnd + iBlkMsk) & ~iBlkMsk);
2912 BuildGammaArray(physStart, physEnd);
2919 && physStart + (curBlk << iBlkLenLog2) < physEnd
2920 && (cchBlk = iGamma[curBlk]) != KNoCacheBlock )
2922 // set up instance variables for WriteDataToUser()
2923 iPhysStart = physStart + (curBlk << iBlkLenLog2);
2924 iPhysEnd = iPhysStart + iBlkLen;
2925 iIntBuf = IdxToCchMem(cchBlk);
2927 if ((r = WriteDataToUser(&iIntBuf[I64LOW(iReqCur - iPhysStart)])) == KErrNone)
2930 iLstUsdCchEnt = iGamma[curBlk];
2935 *aAllDone = (iReqCur >= iReqEnd);
2937 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rdc:%d,%d", *aAllDone, r));
2938 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED_EXIT2, this, r );
2943 TInt DMmcMediaDriverFlash::WriteDataToUser(TUint8* aBufPtr)
2945 // write the data from the most recent read operation to the user descriptor
2948 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_ENTRY, this );
2949 TInt r = KErrNotSupported;
2951 // get range of data to read out of internal buffer
2953 TInt len = I64LOW(UMin(iPhysEnd, iReqEnd) - iReqCur);
2954 TPtrC8 extrView(aBufPtr, len);
2956 // write data from internal buffer
2957 TUint usrOfst = I64LOW(iReqCur - iReqStart);
2959 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_LATENCY1, "Begin writing user data" );
2960 #if defined(__DEMAND_PAGING__) && !defined(__WINS__)
2961 if (DMediaPagingDevice::PageInRequest(*iCurrentReq))
2962 r=iCurrentReq->WriteToPageHandler((TUint8 *)(&extrView[0]), len, usrOfst);
2964 #endif // __DEMAND_PAGING__
2965 r = iCurrentReq->WriteRemote(&extrView,usrOfst);
2967 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_LATENCY2, "End writing user data" );
2969 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_EXIT, this, r );
2973 TInt DMmcMediaDriverFlash::ReadDataFromUser(TDes8& aDes, TInt aOffset)
2975 OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_READDATAFROMUSER_ENTRY ,"DMmcMediaDriverFlash::ReadDataFromUser;aOffset=%d;this=%x", aOffset, (TUint) this);
2976 TInt r = KErrNotSupported;
2978 if (DMediaPagingDevice::PageOutRequest(*iCurrentReq))
2980 r = iCurrentReq->ReadFromPageHandler((TAny*) aDes.Ptr(), aDes.MaxLength(), aOffset);
2981 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT1, this, r );
2985 #endif // #ifndef __WINS__
2986 r = iCurrentReq->ReadRemote(&aDes, aOffset);
2988 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT2, this, r );
2992 TInt DMmcMediaDriverFlash::AdjustPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength)
2994 // Retrieve next Physical memory fragment and adjust the start pointer and length with
2995 // respect to the set offset {iFragOfset}.
2996 // Note the offset may encompass multiple memory fragments.
2999 OstTraceExt3(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_ENTRY, "DMmcMediaDriverFlash::AdjustPhysicalFragment;aPhysAddr=%x;aPhysLength=%d;this=%x", (TUint) aPhysAddr, aPhysLength, (TUint) this);
3000 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:APF"));
3002 TInt err = KErrNone;
3003 TInt offset = iFragOfset;
3007 err = iCurrentReq->GetNextPhysicalAddress(aPhysAddr, aPhysLength);
3009 if (err != KErrNone)
3011 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_EXIT1, this, err );
3015 if (offset >= aPhysLength) // more offset than in this physical chunk
3017 offset -= aPhysLength;
3021 // offset < physLength
3022 // offset lies within the memory chunk
3023 // Adjust length and address for first transfer
3024 aPhysLength -= offset;
3025 aPhysAddr += offset;
3029 } while (offset >= 0);
3031 iFragOfset = 0; // reset offset now complete
3035 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_EXIT2, this, KErrNoMemory );
3036 return KErrNoMemory;
3040 // DMAHelper ensures memory is dma aligned
3041 if ( (aPhysAddr & (iSocket->DmaAlignment()-1) ) )
3043 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lr:Memory Fragment Not Word Aligned!"));
3044 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_DMA, "Memory fragment not word aligned");
3045 Panic(ENotDMAAligned);
3049 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:APF physAddr(0x%x), physLength(%d)",aPhysAddr, aPhysLength));
3050 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_EXIT3, this, err );
3054 TInt DMmcMediaDriverFlash::PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength)
3056 // Retrieves the first Physical memory fragment and determines the type of the next transfer
3057 // Next transfer may either be the last block (end not block aligned) or a block may straddle
3058 // memory fragments.
3061 OstTraceExt4(TRACE_FLOW, DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_ENTRY, "DMmcMediaDriverFlash::PrepareFirstPhysicalFragment;aPhysAddr=%x;aPhysLength=%d;aLength=%x;this=%x", (TUint) aPhysAddr, aPhysLength, (TUint) aLength, (TUint) this);
3062 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF"));
3065 r = AdjustPhysicalFragment(aPhysAddr, aPhysLength);
3069 TUint len = I64LOW(iReqEnd & iBlkMsk);
3070 if ( ((TUint32)aPhysLength >= aLength) && len )
3072 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF-end block"));
3073 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_EB, "End block");
3074 //next iteration will be an IPC for the end block
3075 //There is enough space in physical memory to fit
3076 //the extended read, but exceeds boundary for this request.
3078 iRdROB |= KIPCSetup; // IPC setup for next iteration
3082 if (aPhysLength & iBlkMsk)
3084 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF-straddles boundary"));
3085 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_SB, "Straddles boundary");
3086 // block must be straddling a fragment boundary
3087 // Next iteration must be an IPC
3088 iRdROB |= KIPCSetup;
3090 // Calculate the offset into the next memory block
3091 iFragOfset = I64LOW(iBlkLen - (aPhysLength & iBlkMsk));
3092 aPhysLength &= ~iBlkMsk;
3096 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:PFPF err(%d), physAddr(0x%x), physLength(%d)",r, aPhysAddr, aPhysLength));
3097 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_EXIT, this, r );
3102 void DMmcMediaDriverFlash::PrepareNextPhysicalFragment()
3104 // Retrieves next Physical memory fragment and determines the type of the next transfer
3105 // Next transfer may either be the last block (end not block aligned) or a block may straddle
3106 // memory fragments.
3109 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_ENTRY );
3110 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF"));
3111 TInt err = KErrNone;
3112 TPhysAddr physAddr = 0;
3113 TInt physLength = 0;
3115 err = AdjustPhysicalFragment(physAddr, physLength);
3117 if (err == KErrNone)
3119 if (iPhysEnd+physLength >= iReqEnd)
3121 //Last physical transfer ...
3122 TUint len = I64LOW(iReqEnd & iBlkMsk);
3125 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF-end block"));
3126 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_EB, "End block" );
3128 // end point not block aligned!
3129 // next iteration must be an IPC call
3130 iRdROB |= KIPCSetup;
3135 physLength = I64LOW(iDbEnd - iPhysEnd);
3139 if (physLength & iBlkMsk)
3141 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF-straddles boundary"));
3142 OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_SB, "Straddles boundary" );
3144 // block must be straddling a fragment boundary
3145 // Next iteration must be an IPC
3146 iRdROB |= KIPCSetup;
3148 // Calculate the offset into the next memory block
3149 iFragOfset = I64LOW(iBlkLen - (physLength & iBlkMsk));
3150 physLength &= ~iBlkMsk;
3153 iPhysEnd += physLength;
3156 iSession->MoreDataAvailable( (physLength >> KDiskSectorShift), (TUint8*) physAddr, err);
3157 iSecondBuffer = EFalse;
3158 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:PNPF"));
3159 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_EXIT );
3162 TUint8* DMmcMediaDriverFlash::ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength)
3164 // Assume the cache has been drained before this function is called and so
3165 // the first block is not in the cache. The length of the allocated range is
3166 // either aEnd - aStart, or enough blocks such that the next block to read
3167 // is already available in the cache, and so will be read when
3168 // ReadDataUntilCacheExhausted() is called from the callback DFC.
3171 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_RESERVEREADBLOCKS_ENTRY, this );
3172 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rrb:%lx,%lx", aStart, aEnd));
3174 __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(ERRBStAlign));
3175 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ERRBStPos));
3176 __ASSERT_DEBUG(aEnd > aStart, Panic(ERRBNotPositive));
3177 __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(ERRBEndAlign));
3178 __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(ERRBEndPos));
3179 __ASSERT_DEBUG(!iDoDoubleBuffer, Panic(ENoDBSupport));
3180 __ASSERT_CACHE(CacheInvariant(), Panic(ERRBCchInv));
3181 __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ERRBExist));
3185 BuildGammaArray(aStart, aEnd);
3187 // reposition start index at 0 if the full range would run off the end of the
3188 // buffer. This is heuristic - enabling a longer multi-block may cost some
3189 // cached reads. However, assume long reads do not generally re-read the same
3190 // data, and are used for streaming large amounts of data into memory.
3192 const TInt blocksInRange = I64LOW((aEnd - aStart) >> iBlkLenLog2);
3193 TInt startIndex = (iLstUsdCchEnt + 1) % iBlocksInBuffer;
3194 if (startIndex + blocksInRange > iBlocksInBuffer)
3197 // starting at startIndex, increase the range until it covers aEnd - aStart,
3198 // or until the next block to read is available in the cache.
3205 // range allocated for entire read
3206 blkCnt == blocksInRange
3207 // next block already exists in buffer and has not been overwritten
3208 // by existing multi-block read
3209 || ( iGamma[blkCnt] != KNoCacheBlock
3210 && ( iGamma[blkCnt] < startIndex
3211 || iGamma[blkCnt] >= startIndex + blkCnt ) ) );
3215 } while (! finished);
3217 iLstUsdCchEnt = startIndex + blkCnt - 1;
3219 if (blkCnt < 1) blkCnt = 1; //RBW required < 1 block to be read
3221 OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_RESERVEREADBLOCKS_RANGE, "blocksInRange=%d; blkCnt=%d", blocksInRange, blkCnt );
3223 TUint32 lengthInBytes = blkCnt << iBlkLenLog2;
3224 *aLength = lengthInBytes;
3225 MarkBlocks(aStart, aStart + lengthInBytes, startIndex);
3227 raby = IdxToCchMem(startIndex);
3229 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rrb:%x", (TUint32) raby));
3231 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEREADBLOCKS_EXIT, this, ( TUint )( raby ) );
3236 TUint8* DMmcMediaDriverFlash::ReserveWriteBlocks(TInt64 aStart, TInt64 aEnd, TUint* aRBM)
3238 // reserve a range of blocks in the buffer. If the block containing aStart or aEnd
3239 // are already in the buffer, attempts to position on them. This can save one or two
3242 // This function is linear in the number of blocks - it runs through the array
3245 // aStart and aEnd are not necessarily block aligned - the function uses alignment
3246 // information to minimize RBMs.
3249 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_ENTRY, this );
3250 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rwb:%lx,%lx", aStart, aEnd));
3252 TInt64 physStart = aStart & ~iBlkMsk;
3253 TInt64 physEnd = (aEnd + iBlkMsk) & ~iBlkMsk;
3255 __ASSERT_DEBUG(TotalSizeInBytes() > physStart, Panic(ERWBStPos));
3256 __ASSERT_DEBUG(aEnd > aStart, Panic(ERWBNotPositive));
3257 __ASSERT_DEBUG(TotalSizeInBytes() >= physEnd, Panic(ERWBEndPos));
3258 __ASSERT_DEBUG(iDoPhysicalAddress || iDoDoubleBuffer || (!iDoDoubleBuffer && !iDoPhysicalAddress && physEnd - physStart <= (TInt64)iMaxBufSize), Panic(ERWBOverflow));
3259 __ASSERT_CACHE(CacheInvariant(), Panic(ERWBCchInv));
3261 const TBool firstPartial = (aStart & iBlkMsk) != 0;
3262 const TBool lastPartial = (aEnd & iBlkMsk) != 0;
3264 const TInt blkCnt = I64LOW((physEnd - physStart) >> iBlkLenLog2);
3265 OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_RANGE, "blkCnt=%d", blkCnt );
3267 TBool startUsed = EFalse;
3268 TBool endUsed = EFalse;
3270 TUint8* raby = NULL;
3275 // If we're double-buffering, then the entire cache will be re-used
3276 // continuously. Rather than continually reserve blocks during each
3277 // transfer we calculate the blocks that will be present after all
3278 // transfers have completed.
3287 // check if the first or last blocks are already in the buffer.
3288 TInt fst = -1, lst = -1;
3289 const TInt64 lstBlk = physEnd - iBlkLen;
3291 for (i = 0; i < iBlocksInBuffer; ++i)
3293 if (iCachedBlocks[i] == physStart)
3296 if (iCachedBlocks[i] == lstBlk)
3300 const TBool firstUsable = (fst != -1) && (iBlocksInBuffer - fst) >= blkCnt;
3301 const TBool lastUsable = (lst != -1) && lst >= (blkCnt - 1);
3303 if (iDoPhysicalAddress)
3305 if ( (firstPartial || lastPartial) && blkCnt <= 2)
3307 //Physical addressing not to be used.
3308 //more efficent to use local Cache copying
3309 iDoPhysicalAddress = EFalse;
3310 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_EXIT1, this, ( TUint )( raby ) );
3317 const TBool firstPres = (fst != -1);
3318 const TBool lastPres = (lst != -1);
3320 if (firstPartial && firstPres)
3322 // move to minor buffer
3323 memcpy(iMinorBuf, IdxToCchMem(fst), iBlkLen);
3325 if (lastPartial && lastPres)
3327 // move to beginning of cache
3328 memcpy(iCacheBuf, IdxToCchMem(lst), iBlkLen);
3331 InvalidateCache(physStart,physEnd);
3335 //re-mark beginning of cache
3336 MarkBlocks((physEnd-iBlkLen), physEnd, 0);
3346 if (firstPartial && !firstPres)
3352 if (lastPartial && !lastPres)
3356 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_EXIT2, this, ( TUint )( raby ) );
3359 } // if (iDoPhysicalAddress)
3361 if (!firstUsable && !lastUsable)
3365 idx = iSecondBuffer ? iBlocksInBuffer >> 1 : 0;
3369 idx = (iLstUsdCchEnt + 1) % iBlocksInBuffer;
3370 if (idx + blkCnt > iBlocksInBuffer)
3374 else if (firstUsable && ! lastUsable)
3378 else if (! firstUsable && lastUsable)
3380 idx = lst - (blkCnt - 1);
3382 else // (lastUsable && firstUsable)
3384 if (firstPartial || ! lastPartial)
3387 idx = lst - (blkCnt - 1);
3390 MarkBlocks(physStart, physEnd, idx);
3392 // if the range started or ended on a partial block, but could not
3393 // be allocated on that existing block, and the existing block is
3394 // somewhere in the cache, then memcpy() that block to the end of the
3395 // range. used is not the same as usable - both the start and end
3396 // blocks may be usable, through not in the same range, or any range.
3398 const TInt startExtent = I64LOW(aStart & iBlkMsk);
3399 TBool firstInTemp = EFalse;
3400 startUsed = (idx == fst);
3401 if (! startUsed && firstPartial && fst != -1)
3403 // if the range has started at index occupied by the last block then
3404 // temporarily copy to minor buffer. This is unnecessary when the
3405 // last block is not partial because the last block does not need to
3408 if (idx == lst && lastPartial)
3410 firstInTemp = ETrue;
3411 memcpy(iMinorBuf, IdxToCchMem(fst), startExtent);
3415 memcpy(IdxToCchMem(idx), IdxToCchMem(fst), startExtent);
3421 endUsed = (idx + blkCnt - 1 == lst);
3422 if (! endUsed && lastPartial && lst != -1)
3424 const TInt endOffset = I64LOW(aEnd & iBlkMsk);
3425 const TInt endExtent = iBlkLen - endOffset;
3426 memcpy(IdxToCchMem(idx + blkCnt - 1) + endOffset, IdxToCchMem(lst) + endOffset, endExtent);
3431 memcpy(IdxToCchMem(idx), iMinorBuf, startExtent);
3433 // start reclaiming at block following this range
3434 iLstUsdCchEnt = idx + blkCnt - 1;
3435 raby = IdxToCchMem(idx);
3438 // work out if read-before-write required
3442 // first index was not already in range, and does not start on block boundary
3443 if (firstPartial && ! startUsed)
3446 // last index was not already in range, and does not end on block boundary
3447 if (lastPartial && ! endUsed)
3450 // only use one pre-read if contained in single block
3451 if (blkCnt == 1 && *aRBM == (KWtRBMFst | KWtRBMLst))
3455 // When double-buffering, RMW for the last block is stored in the
3456 // minor buffer and writen during the last transfer, so flag this
3457 // seperately (as aRBM is used for the initial RMW Read then subsequently cleared).
3459 if(iDoDoubleBuffer && (*aRBM & KWtRBMLst))
3463 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rwb:%x", (TUint32) raby));
3465 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_EXIT3, this, ( TUint )( raby ) );
3469 void DMmcMediaDriverFlash::MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex)
3471 // mark range of blocks for media range. If existing cache entries for any part of
3472 // the cache are already in the buffer they are invalidated.
3475 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_MARKBLOCKS_ENTRY, this );
3476 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:mb:%lx,%lx,%d", aStart, aEnd, aStartIndex));
3478 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EMBStPos));
3479 __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(EMBStAlign));
3480 __ASSERT_DEBUG(aEnd > aStart, Panic(EMBNotPositive));
3481 __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EMBEndPos));
3482 __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(EMBEndAlign));
3483 __ASSERT_DEBUG(aStartIndex + (TInt)((aEnd - aStart) >> iBlkLenLog2) <= iBlocksInBuffer, Panic(EMBOverflow));
3484 __ASSERT_CACHE(CacheInvariant(), Panic(EMBCchInvPre));
3488 for (i = 0; i < aStartIndex; ++i)
3490 if (iCachedBlocks[i] >= aStart && iCachedBlocks[i] < aEnd)
3491 iCachedBlocks[i] = KInvalidBlock;
3494 TInt blkCnt = I64LOW((aEnd - aStart) >> iBlkLenLog2);
3495 OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_MARKBLOCKS_RANGE, "blkCnt=%d", blkCnt );
3496 for (i = aStartIndex; i < aStartIndex + blkCnt; ++i)
3497 iCachedBlocks[i] = aStart + (static_cast<TUint32>(i - aStartIndex) << iBlkLenLog2);
3499 for (i = aStartIndex + blkCnt; i < iBlocksInBuffer; ++i)
3501 if (iCachedBlocks[i] >= aStart && iCachedBlocks[i] < aEnd)
3502 iCachedBlocks[i] = KInvalidBlock;
3505 __ASSERT_CACHE(CacheInvariant(), Panic(EMBCchInvPost));
3506 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_MARKBLOCKS_EXIT, this );
3510 void DMmcMediaDriverFlash::BuildGammaArray(TInt64 aStart, TInt64 aEnd)
3512 // iGamma is an array of indexes that correspond to cached blocks starting
3513 // from aStart. iGamma[0] is the index of aStart, iGamma[1] is the index of
3514 // aStart + iBlkLen, and so on. Building an array here means that all of
3515 // the available cached entries can be found in linear time instead of
3516 // quadratically searching through the array for each block.
3519 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_ENTRY, this );
3520 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:bga:%lx,%lx", aStart, aEnd));
3522 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EBGAStPos));
3523 __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(EBGAStAlign));
3524 __ASSERT_DEBUG(aEnd > aStart, Panic(EBGANotPositive));
3525 __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EBGAEndPos));
3526 __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(EBGAEndAlign));
3527 __ASSERT_DEBUG(aEnd - aStart <= (TInt64) iMaxBufSize, Panic(EBGAOverflow));
3528 __ASSERT_CACHE(CacheInvariant(), Panic(EBGACchInv));
3530 // KNoCacheBlock = (0xff) x 4
3531 TUint blocksInRange = I64LOW((aEnd - aStart) >> iBlkLenLog2);
3532 OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_RANGE, "blocksInRange=%d", blocksInRange );
3533 memset(iGamma, 0xff, sizeof(*iGamma) * blocksInRange);
3536 for (TInt i = 0; ( (blocksInRange > 0 ) && (i < iBlocksInBuffer) ); ++i)
3538 blkAddr = iCachedBlocks[i];
3539 if (blkAddr >= aStart && blkAddr < aEnd)
3541 iGamma[I64LOW((blkAddr - aStart) >> iBlkLenLog2)] = i;
3545 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_EXIT, this );
3548 void DMmcMediaDriverFlash::InvalidateCache()
3550 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_INVALIDATECACHE1_ENTRY );
3551 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ich"));
3553 // KInvalidBlock = (0xff) x 4
3554 memset(iCachedBlocks, 0xff, sizeof(*iCachedBlocks) * iBlocksInBuffer);
3555 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_INVALIDATECACHE1_EXIT );
3558 // Invalidate any cache entries from aStart to aEnd
3559 // This is for DMA writes and is to prevent the cache becoming inconsistent with the media.
3560 void DMmcMediaDriverFlash::InvalidateCache(TInt64 aStart, TInt64 aEnd)
3562 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_INVALIDATECACHE2_ENTRY, this );
3563 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ich:%lx,%lx", aStart, aEnd));
3565 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EBGAStPos));
3566 __ASSERT_DEBUG(aEnd > aStart, Panic(EBGANotPositive));
3567 __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EBGAEndPos));
3569 const TInt blkCnt = I64LOW((aStart - aEnd) >> iBlkLenLog2);
3570 OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_INVALIDATECACHE_RANGE, "blocksInRange=%d", blkCnt );
3572 __ASSERT_CACHE(CacheInvariant(), Panic(EBGACchInv));
3574 TInt64 endBlk = (blkCnt == 0) ? (aStart+iBlkLen) : aEnd;
3576 for (TInt i = 0; i < iBlocksInBuffer; ++i)
3578 const TInt64 blkAddr = iCachedBlocks[i];
3579 if (blkAddr >= aStart && blkAddr < endBlk)
3580 iCachedBlocks[i] = KInvalidBlock;
3582 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_INVALIDATECACHE2_EXIT, this );
3585 TUint8* DMmcMediaDriverFlash::IdxToCchMem(TInt aIdx) const
3587 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_IDXTOCCHMEM_ENTRY, this );
3588 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:icm:%d", aIdx));
3590 __ASSERT_DEBUG(aIdx >= 0, Panic(EICMNegative));
3591 __ASSERT_DEBUG(aIdx < iBlocksInBuffer, Panic(EICMOverflow));
3593 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_IDXTOCCHMEM_EXIT, this );
3594 return &iCacheBuf[aIdx << iBlkLenLog2];
3597 TInt DMmcMediaDriverFlash::CchMemToIdx(TUint8* aMemP) const
3599 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CCHMEMTOIDX_ENTRY, this );
3600 __ASSERT_DEBUG((aMemP >= iCacheBuf) && (aMemP < iCacheBuf + (iBlocksInBuffer << iBlkLenLog2)), Panic(ECMIOverflow));
3602 return((aMemP - iCacheBuf) >> iBlkLenLog2);
3606 TBool DMmcMediaDriverFlash::CacheInvariant()
3608 // check each cache entry refers to a valid block and that no two
3609 // entries cover the same block. This algorithm is quadratic in
3610 // the cache length.
3613 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CACHEINVARIANT_ENTRY, this );
3614 for (TInt i = 0; i < iBlocksInBuffer; ++i)
3616 if (iCachedBlocks[i] == KInvalidBlock)
3619 if ((iCachedBlocks[i] & iBlkMsk) != 0)
3622 if (iCachedBlocks[i] >= TotalSizeInBytes())
3625 for (TInt j = i + 1; j < iBlocksInBuffer; ++j)
3627 if (iCachedBlocks[i] == iCachedBlocks[j])
3632 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_CACHEINVARIANT_EXIT, this );
3637 void DMmcMediaDriverFlash::NotifyPowerDown()
3639 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_NOTIFYPOWERDOWN_ENTRY );
3640 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Mmc:NotifyPowerDown"));
3642 iSessionEndDfc.Cancel();
3643 iDataTransferCallBackDfc.Cancel();
3647 // need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once.
3649 iStack->CancelSession(iSession);
3651 CompleteRequest(KErrNotReady);
3652 iMedReq = EMReqIdle;
3653 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_NOTIFYPOWERDOWN_EXIT );
3656 void DMmcMediaDriverFlash::NotifyEmergencyPowerDown()
3658 OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_NOTIFYEMERGENCYPOWERDOWN_ENTRY );
3659 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NotifyEmergencyPowerDown"));
3661 iSessionEndDfc.Cancel();
3662 iDataTransferCallBackDfc.Cancel();
3664 TInt r=KErrNotReady;
3669 // need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once.
3671 iStack->CancelSession(iSession);
3674 iMedReq = EMReqIdle;
3675 OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_NOTIFYEMERGENCYPOWERDOWN_EXIT );
3678 TInt DMmcMediaDriverFlash::Request(TLocDrvRequest& aRequest)
3680 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_REQUEST_ENTRY, this );
3681 __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x id %d",&aRequest,aRequest.Id()));
3682 TInt r=KErrNotSupported;
3683 TInt id=aRequest.Id();
3684 OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_ID, "Request=0x%08x; Request ID=%d", (TUint) &aRequest, id);
3686 #if defined (__TEST_PAGING_MEDIA_DRIVER__)
3687 DThread* client=aRequest.Client();
3688 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("Client:0x%08x",client));
3689 OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_CLIENT, "Request client=0x%08x", (TUint) client);
3690 #endif // __TEST_PAGING_MEDIA_DRIVER__
3692 // First handle requests that can be handled without deferring
3693 if(id==DLocalDrive::ECaps)
3695 TLocalDriveCapsV6& c = *(TLocalDriveCapsV6*)aRequest.RemoteDes();
3696 TLocDrv& drive = *aRequest.Drive();
3698 c.iSize = drive.iPartitionLen;
3699 c.iPartitionType = drive.iPartitionType;
3700 c.iHiddenSectors = (TUint) (drive.iPartitionBaseAddr >> KDiskSectorShift);
3701 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT1, this, r );
3705 // All other requests must be deferred if a request is currently in progress
3709 #if defined(__TEST_PAGING_MEDIA_DRIVER__)
3710 if (DMediaPagingDevice::PageInRequest(*iCurrentReq))
3711 iMmcStats.iReqPage++;
3713 iMmcStats.iReqNormal++;
3714 #endif // __TEST_PAGING_MEDIA_DRIVER__
3716 // a request is already in progress, so hold on to this one
3717 __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x ret 1",&aRequest));
3718 OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_IN_PROGRESS, "Request in progress=0x%08x", (TUint) &aRequest);
3719 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT2, this, KMediaDriverDeferRequest );
3720 return KMediaDriverDeferRequest;
3724 iCurrentReq=&aRequest;
3725 TUint partitionType = iCurrentReq->Drive()->iPartitionType;
3726 TBool readOnly = (partitionType == KPartitionTypeRofs || partitionType == KPartitionTypeROM);
3732 #if defined(__DEMAND_PAGING__)
3733 case DMediaPagingDevice::ERomPageInRequest:
3734 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Request(ERomPageInRequest)"));
3735 BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_MMC,iCurrentReq);
3736 OstTraceDef0( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_ROM_PAGE_IN, "ROM page-in request");
3739 case DMediaPagingDevice::ECodePageInRequest:
3740 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Request(ECodePageInRequest)"));
3741 BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_MMC,iCurrentReq);
3742 OstTraceDef0( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_CODE_PAGE_IN, "Code page-in request");
3745 #endif // __DEMAND_PAGING__
3747 case DLocalDrive::EQueryDevice:
3748 r = KErrNotSupported;
3751 case DLocalDrive::ERead:
3754 case DLocalDrive::EWrite:
3757 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT3, this, KErrNotSupported );
3758 return KErrNotSupported;
3762 case DLocalDrive::EFormat:
3765 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT4, this, KErrNotSupported );
3766 return KErrNotSupported;
3771 #if defined __TEST_PAGING_MEDIA_DRIVER__
3772 case DLocalDrive::EControlIO:
3774 r = HandleControlIORequest();
3779 case DLocalDrive::EPasswordUnlock:
3780 case DLocalDrive::EPasswordLock:
3781 case DLocalDrive::EPasswordClear:
3782 // Don't allow passords on internal MMC; one reason is that this may be used for paging and
3783 // we can't really stop paging just because the password hasn't been supplied
3785 r = KErrNotSupported;
3789 case DLocalDrive::EPasswordErase:
3791 r = LaunchRPIErase();
3792 // This will complete the request in the event of an error
3794 PartitionInfoComplete(r);
3796 r = KErrNone; // ensures to indicate asynchronoous completion
3799 case DLocalDrive::EWritePasswordStore:
3802 // If the card is ready and locked, request the stack to perform the
3803 // auto-unlock sequence. This is required, as the stack only performs
3804 // automatic unlocking during power-up, and the stack may already be powered.
3806 r = KErrNone; // asynchronous completion
3808 if(iCard->IsReady() && iCard->IsLocked())
3810 iSession->SetupCIMAutoUnlock();
3811 if(EngageAndSetRequest(EMReqWritePasswordData, 0) != KErrNone)
3813 // If error, complete with KErrNone anyway
3814 // - The password store has been set, any errors
3815 // will be reported on the next access.
3816 CompleteRequest(KErrNone);
3821 CompleteRequest(KErrNone);
3825 case DLocalDrive::EEnlarge:
3826 case DLocalDrive::EReduce:
3833 __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x cmp %d",&aRequest,r));
3837 iMedReq = EMReqIdle;
3839 SetCurrentConsumption(KIdleCurrentInMilliAmps);
3842 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT5, this, r );
3846 void DMmcMediaDriverFlash::Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg)
3848 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DISCONNECT_ENTRY, this );
3849 // Complete using the default implementation
3850 DMediaDriver::Disconnect(aLocalDrive, aMsg);
3851 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DISCONNECT_EXIT, this );
3855 TUint8* DMmcMediaDriverFlash::GetCachedBlock(TInt64 aMdAddr)
3857 // return cache block for media at aMdAddr, 0 if not found.
3858 // This is a debug function to determine whether or not a block is in
3859 // the cache. It should not be used for general block retrieval.
3860 // If there are m blocks in the cache, and n in the requested range,
3861 // this function is o(mn), whereas BuildGammaArray() is theta(m).
3864 OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_GETCACHEDBLOCK_ENTRY, this );
3865 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:gcb:%lx", aMdAddr));
3867 __ASSERT_DEBUG((aMdAddr & iBlkMsk) == 0, Panic(EGCBAlign));
3868 __ASSERT_DEBUG(TotalSizeInBytes() > aMdAddr, Panic(EGCBPos));
3869 __ASSERT_CACHE(CacheInvariant(), Panic(EGCBCchInv));
3871 for (TInt i = 0; i < iBlocksInBuffer; ++i)
3873 if (iCachedBlocks[i] == aMdAddr)
3875 TUint8* raby = IdxToCchMem(i);
3876 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:gcb:%x", (TUint32) raby));
3877 OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_GETCACHEDBLOCK_EXIT1, this, ( TUint )( raby ) );
3882 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:gcb:0"));
3883 OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_GETCACHEDBLOCK_EXIT2, this );
3886 #endif // _DEBUG_CACHE
3889 #if defined(__TEST_PAGING_MEDIA_DRIVER__)
3891 Handles a ControlIO request to the MMC media driver.
3892 made by one of the MMC paging tests
3896 @return Corresponding Symbian OS error code
3898 TInt DMmcMediaDriverFlash::HandleControlIORequest()
3900 const TInt command = iCurrentReq->Int0();
3901 TAny* aParam1 = iCurrentReq->Ptr1();
3902 // TAny* aParam2 = iCurrentReq->Ptr2();
3904 TInt r = KErrCompletion;
3906 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("[MD : ] HandleControlIORequest aCommand: 0x%x", command));
3913 DThread* pC = iCurrentReq->Client();
3914 DThread* pT = iCurrentReq->RemoteThread();
3917 Kern::ThreadRawWrite(pT, aParam1, &iMmcStats, sizeof(iMmcStats), pC);
3919 iMmcStats.iReqNormal=0;
3920 iMmcStats.iNormalFragmenting=0;
3921 iMmcStats.iClashFragmenting=0;
3932 #endif // __TEST_PAGING_MEDIA_DRIVER__
3937 DECLARE_EXTENSION_PDD()
3939 // NB if the media driver has been defined as a kernel extension in the .OBY/.IBY file
3940 // i.e the "extension" keyword has been used rather than "device", then an instance of
3941 // DPhysicalDeviceMediaMmcFlash will already have been created by InitExtension(). In this
3942 // case the kernel will see that an object of the same name already exists and delete the
3944 return new DPhysicalDeviceMediaMmcFlash;
3946 DECLARE_STANDARD_EXTENSION()
3948 __KTRACE_OPT(KBOOT,Kern::Printf("Creating MMCDrv PDD"));
3950 DPhysicalDeviceMediaMmcFlash* device = new DPhysicalDeviceMediaMmcFlash;
3956 r=Kern::InstallPhysicalDevice(device);
3957 __KTRACE_OPT(KBOOT,Kern::Printf("Installing MMCDrv PDD in kernel returned %d",r));
3959 __KTRACE_OPT(KBOOT,Kern::Printf("Mmc extension entry point drive returns %d",r));