// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// drivers/medmmc/medmmc.h
//
//
#ifndef MEDMMC_H
#define MEDMMC_H
#include <drivers/locmedia.h>
#include <e32const.h>
#if defined(__DEMAND_PAGING__)
// If in debug mode, enable paging stats and their retrieval using DLocalDrive::EControlIO
#if defined( _DEBUG)
#define __TEST_PAGING_MEDIA_DRIVER__
#endif
#include "mmcdp.h"
#endif
// Enable this macro to debug cache:
// NB The greater the number of blocks, the slower this is...
//#define _DEBUG_CACHE
#ifdef _DEBUG_CACHE
#define __ASSERT_CACHE(c,p) (void)((c)||(p,0))
#else
#define __ASSERT_CACHE(c,p)
#endif
const TInt KDiskSectorSize = 512;
const TInt KDiskSectorShift = 9;
class DMmcMediaDriverFlash : public DMediaDriver
{
public:
DMmcMediaDriverFlash(TInt aMediaId);
~DMmcMediaDriverFlash();
// ...from DMediaDriver
virtual void Close();
// replacing pure virtual
virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage*);
virtual TInt Request(TLocDrvRequest& aRequest);
virtual TInt PartitionInfo(TPartitionInfo& anInfo);
virtual void NotifyPowerDown();
virtual void NotifyEmergencyPowerDown();
// For creation by DPhysicalDeviceMediaMmcFlash
TInt DoCreate(TInt aMediaId);
private:
enum TPanic
{
EDRInUse = 0x0000, EDRStart, EDRNotPositive, EDREnd,
ELRRequest = 0x0010, ELRStart, ELRNotPositive, ELREnd, ELRCached,
EDWInUse = 0x0020, EDWStart, EDWNotPositive, EDWEnd,
EDFInUse = 0x0030, EDFStart, EDFNotPositive, EDFEnd, ENotMmcSocket,
ELWRequest = 0x0040, ELWStart, ELWFmtStAlign, ELWNotPositive, ELWEnd, ELWFmtEndAlign,
ELWLength, ELFStart, ELFEnd, ELFNotPositive,
ERPIInUse = 0x0050,
EPCInUse = 0x0060, EPCFunc,
ESECBQueued = 0x0070,
EDSEDRequest = 0x0080, EDSEDNotErrComplete,
ECRReqIdle = 0x0090, ECRRequest,
ERRBStAlign = 0x00a0, ERRBStPos, ERRBNotPositive, ERRBEndAlign, ERRBEndPos,
ERRBOverflow, ERRBCchInv, ERRBExist,
ERWBStPos = 0x00b0, ERWBNotPositive, ERWBEndPos, ERWBOverflow, ERWBCchInv,
EMBStPos = 0x00c0, EMBStAlign, EMBNotPositive, EMBEndPos, EMBEndAlign,
EMBOverflow, EMBCchInvPre, EMBCchInvPost,
EBGAStPos = 0x00d0, EBGAStAlign, EBGANotPositive, EBGAEndPos, EBGAEndAlign,
EBGAOverflow, EBGACchInv,
EICMNegative = 0x00e0, EICMOverflow, ECMIOverflow,
EGCBAlign = 0x00f0, EGCBPos, EGCBCchInv,
ECFSessPtrNull = 0x0100, // Code Fault - session pointer NULL
EDBNotEven = 0x0110, // Not and even number of blocks in the buffer cache
EDBCBQueued = 0x0111, // The data transfer callback is already queued
EDBLength = 0x0112, // The length of data to transfer in data transfer callback is not positive
EDBLengthTooBig = 0x0113, // The length of data to transfer in data transfer callback is too big
EDBOffsetTooBig = 0x0114, // The Offset into the user data buffer is too big
EDBCacheInvalid = 0x0115, // The cache is invalid at the end of data transfer
EDBNotOptimal = 0x0116, // Due to Cache size DB functionality will never be utilised
ENoDBSupport = 0x0120, // DMA request arrived but PSL does not support double buffering
ENotDMAAligned = 0x0121,
EArrayBoundsExc = 0x0122 // Array bounds exceeded (either too small or too large)
};
static void Panic(TPanic aPnc);
enum TMediaRequest
{
EMReqRead = 0,
EMReqWrite = 1,
EMReqFormat = 2,
EMReqPtnInfo,
EMReqPswdCtrl,
EMReqForceErase,
EMReqUpdatePtnInfo,
EMReqWritePasswordData,
EMReqIdle,
EMReqEMMCPtnInfo,
};
enum TMediaReqType {EMReqTypeNormalRd,EMReqTypeNormalWr,EMReqTypeUnlockPswd,EMReqTypeChangePswd};
enum {KWtRBMFst = 0x00000001, // iWtRBM - Read First Block only
KWtRBMLst = 0x00000002, // iWtRBM - Read Last Block only
KWtMinFst = 0x00000004, // iWtRBM - Write First Block only
KWtMinLst = 0x00000008, // iWtRBM - Write Last Block only
KIPCSetup = 0x00000010, // iRdROB - IPC Setup Next Iteration
KIPCWrite = 0x00000020}; // iRdROB - IPC Write Next Iteration
public:
inline void SetEMmcPartitionMapping(TInt aLocalPtn, TInt aEMmcPtn)
{
__ASSERT_DEBUG((aLocalPtn >= 0) && (aLocalPtn < KMaxLocalDrives), Kern::Fault("Mmc: Array bounds exception", __LINE__));
iEMmcPartitionMappings[aLocalPtn] = aEMmcPtn;
};
inline TInt GetEMmcPartitionMapping(TInt aLocalPtn) const
{
__ASSERT_DEBUG((aLocalPtn >= 0) && (aLocalPtn < KMaxLocalDrives), Kern::Fault("Mmc: Array bounds exception", __LINE__));
return iEMmcPartitionMappings[aLocalPtn];
};
private:
// MMC device specific stuff
TInt DoRead();
TInt DoWrite();
TInt DoFormat();
TInt Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo);
inline DMMCStack& Stack() const;
inline TInt CardNum() const;
inline TMediaRequest CurrentRequest() const;
TInt LaunchRead(TInt64 aStart, TUint32 aLength);
TInt LaunchDBRead();
TInt LaunchPhysRead(TInt64 aStart, TUint32 aLength);
TInt LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq);
TInt LaunchFormat(TInt64 aStart, TUint32 aLength);
TInt LaunchRPIUnlock(TLocalDrivePasswordData& aData);
TInt LaunchRPIRead();
TInt LaunchRPIErase();
TInt DecodePartitionInfo();
TInt WritePartitionInfo();
TInt GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry);
TInt CreateDefaultPartition();
#if defined __TEST_PAGING_MEDIA_DRIVER__
TInt HandleControlIORequest();
#endif
static void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors);
TInt CheckDevice(TMediaReqType aReqType);
static void SessionEndCallBack(TAny* aMediaDriver);
static void SessionEndDfc(TAny* aMediaDriver);
void DoSessionEndDfc();
static void DataTransferCallBack(TAny* aMediaDriver);
static void DataTransferCallBackDfc(TAny* aMediaDriver);
void DoReadDataTransferCallBack();
void DoWriteDataTransferCallBack();
void DoPhysReadDataTransferCallBack();
void DoPhysWriteDataTransferCallBack();
TInt AdjustPhysicalFragment(TPhysAddr &physAddr, TInt &physLength);
TInt PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength);
void PrepareNextPhysicalFragment();
TInt EngageAndSetReadRequest(TMediaRequest aRequest);
TInt EngageAndSetWriteRequest(TMediaRequest aRequest);
TInt EngageAndSetRequest(TMediaRequest aRequest, TInt aCurrent);
void CompleteRequest(TInt aReason);
TInt ReadDataUntilCacheExhausted(TBool* aAllDone);
TInt WriteDataToUser(TUint8* aBufPtr);
TInt ReadDataFromUser(TDes8& aDes, TInt aOffset);
TUint8* ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength);
TUint8* ReserveWriteBlocks(TInt64 aMedStart, TInt64 aMedEnd, TUint* aRBM);
void MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex);
void BuildGammaArray(TInt64 aStart, TInt64 aEnd);
void InvalidateCache();
void InvalidateCache(TInt64 aStart, TInt64 aEnd);
TUint8* IdxToCchMem(TInt aIdx) const;
TInt CchMemToIdx(TUint8* aMemP) const;
TInt DoPasswordOp();
void PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData);
void Reset();
TInt AllocateSession();
TBool isRemovableDrive(TLocDrv& aDrive);
#ifdef _DEBUG_CACHE
TBool CacheInvariant();
TUint8* GetCachedBlock(TInt64 aAddr);
#endif
private:
DMMCStack* iStack; // controller objects
TMMCard* iCard;
DMMCSession* iSession;
DMMCSocket* iSocket;
TInt iCardNumber;
TUint iBlkLenLog2; // cached CSD data
TUint32 iBlkLen;
TInt64 iBlkMsk;
TBool iReadBlPartial;
TUint32 iPrWtGpLen; // preferred write group size in bytes,
TInt64 iPrWtGpMsk;
TInt iReadCurrentInMilliAmps; // power management
TInt iWriteCurrentInMilliAmps;
TUint8* iMinorBuf; // MBR, CMD42, partial read
TUint8* iCacheBuf; // cached buffer
TUint32 iMaxBufSize;
TInt iBlocksInBuffer;
TInt64* iCachedBlocks;
TInt* iGamma; // B lookup, ReserveReadBlocks()
TUint8* iIntBuf; // start of current buffer region
TInt iLstUsdCchEnt; // index of last used cache entry
TLocDrvRequest* iCurrentReq; // Current Request
TMediaRequest iMedReq;
TInt64 iReqStart; // user-requested start region
TInt64 iReqCur; // Currently requested start region
TInt64 iReqEnd; // user-requested end region
TInt64 iPhysStart; // physical region for one operation
TInt64 iPhysEnd; // physical end point for one operation
TInt64 iDbEnd; // Double buffer end point for one operation
TUint64 iEraseUnitMsk;
TUint iWtRBM; // Write - Read Before Modify Flags
TUint iRdROB; // Read - Read Odd Blocks Flags
TInt iFragOfset;
TUint32 iIPCLen;
TUint32 iNxtIPCLen;
TUint32 iBufOfset;
TUint iHiddenSectors; // bootup / password
TMMCCallBack iSessionEndCallBack;
TDfc iSessionEndDfc;
TPartitionInfo* iPartitionInfo;
TMMCMediaTypeEnum iMediaType;
TMMCEraseInfo iEraseInfo;
TBool iMbrMissing;
TInt iMediaId;
DMMCStack::TDemandPagingInfo iDemandPagingInfo;
#if defined(__TEST_PAGING_MEDIA_DRIVER__)
SMmcStats iMmcStats;
#endif // __TEST_PAGING_MEDIA_DRIVER__
TMMCCallBack iDataTransferCallBack; // Callback registered with the MMC stack to perform double-buffering
TDfc iDataTransferCallBackDfc; // ...and the associated DFC queue.
TBool iSecondBuffer; // Specified the currently active buffer
TBool iDoLastRMW; // ETrue if the last double-buffer transfer requires RMW modification
TBool iDoDoubleBuffer; // ETrue if double-buffering is currently active
TBool iDoPhysicalAddress; // ETrue if Physical Addressing is currently active
TBool iCreateMbr;
TBool iReadToEndOfCard; // {Read Only} ETrue if Reading to end of Card
TBool iInternalSlot;
DEMMCPartitionInfo* iMmcPartitionInfo; // Responsible for decoding partitions for embedded devices
TInt iEMmcPartitionMappings[KMaxLocalDrives]; // holds the mapping of emmc partitions
};
#endif