sl@0: // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Media driver for MultiMediaCard Flash device sl@0: // sl@0: // sl@0: sl@0: #include "mmc.h" sl@0: #include "pbusmedia.h" sl@0: #include sl@0: sl@0: #include "OstTraceDefinitions.h" sl@0: #ifdef OST_TRACE_COMPILER_IN_USE sl@0: #include "locmedia_ost.h" sl@0: #ifdef __VC32__ sl@0: #pragma warning(disable: 4127) // disabling warning "conditional expression is constant" sl@0: #endif sl@0: #include "medmmcTraces.h" sl@0: #endif sl@0: sl@0: #if defined(__DEMAND_PAGING__) sl@0: // If in debug mode, enable paging stats and their retrieval using DLocalDrive::EControlIO sl@0: #if defined( _DEBUG) sl@0: #define __TEST_PAGING_MEDIA_DRIVER__ sl@0: #endif sl@0: #include "mmcdp.h" sl@0: #endif sl@0: sl@0: #ifndef BTRACE_PAGING_MEDIA sl@0: #undef BTraceContext8 sl@0: #define BTraceContext8(aCategory,aSubCategory,a1,a2) sl@0: #endif // BTRACE_PAGING_MEDIA sl@0: sl@0: // Enable this macro to debug cache: sl@0: // NB The greater the number of blocks, the slower this is... sl@0: //#define _DEBUG_CACHE sl@0: #ifdef _DEBUG_CACHE sl@0: #define __ASSERT_CACHE(c,p) (void)((c)||(p,0)) sl@0: #else sl@0: #define __ASSERT_CACHE(c,p) sl@0: #endif sl@0: sl@0: sl@0: GLREF_C TInt GetMediaDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry, TUint16& aReservedSectors, const TMMCard* aCardP); sl@0: GLREF_C TBool MBRMandatory(const TMMCard* aCardP); sl@0: GLREF_C TBool CreateMBRAfterFormat(const TMMCard* aCardP); sl@0: GLREF_C TInt BlockSize(const TMMCard* aCardP); sl@0: GLREF_C TInt EraseBlockSize(const TMMCard* aCardP); sl@0: GLREF_C TInt GetCardFormatInfo(const TMMCard* aCardP, TLDFormatInfo& aFormatInfo); sl@0: sl@0: const TInt KStackNumber = 0; sl@0: sl@0: const TInt KDiskSectorSize=512; sl@0: const TInt KDiskSectorShift=9; sl@0: sl@0: const TInt KIdleCurrentInMilliAmps = 1; sl@0: sl@0: const TInt KMBRFirstPartitionEntry=0x1BE; sl@0: sl@0: template sl@0: inline T UMin(T aLeft,T aRight) sl@0: {return(aLeftmmd:crt")); sl@0: sl@0: if (!Kern::QueryVersionSupported(iVersion,aVer)) sl@0: { sl@0: OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_CREATE_EXIT1, this, KErrNotSupported ); sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: DMmcMediaDriverFlash* pD = new DMmcMediaDriverFlash(aMediaId); sl@0: aChannel=pD; sl@0: sl@0: TInt r=KErrNoMemory; sl@0: if (pD) sl@0: r=pD->DoCreate(aMediaId); sl@0: if (r==KErrNone) sl@0: pD->OpenMediaDriverComplete(KErrNone); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("(iStack); } sl@0: sl@0: sl@0: inline TInt DMmcMediaDriverFlash::CardNum() const sl@0: { return iCardNumber; } sl@0: sl@0: sl@0: inline DMmcMediaDriverFlash::TMediaRequest DMmcMediaDriverFlash::CurrentRequest() const sl@0: { return iMedReq; } sl@0: sl@0: sl@0: // Helper sl@0: template sl@0: inline T* KernAlloc(const TUint32 n) sl@0: { return static_cast(Kern::Alloc(n * sizeof(T))); } sl@0: sl@0: // ---- ctor, open, close, dtor ---- sl@0: sl@0: #pragma warning( disable : 4355 ) // this used in initializer list sl@0: DMmcMediaDriverFlash::DMmcMediaDriverFlash(TInt aMediaId) sl@0: :DMediaDriver(aMediaId), sl@0: iMedReq(EMReqIdle), sl@0: iSessionEndCallBack(DMmcMediaDriverFlash::SessionEndCallBack, this), sl@0: iSessionEndDfc(DMmcMediaDriverFlash::SessionEndDfc, this, 1), sl@0: iMediaId(iPrimaryMedia->iNextMediaId), sl@0: iDataTransferCallBack(DMmcMediaDriverFlash::DataTransferCallBack, this), sl@0: iDataTransferCallBackDfc(DMmcMediaDriverFlash::DataTransferCallBackDfc, this, 1) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:mmd")); sl@0: // NB aMedia Id = the media ID of the primary media, iMediaId = the media ID of this media sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash(), iMediaId %d, aMediaId %d\n", iMediaId, aMediaId)); sl@0: OstTraceExt2( TRACE_FLOW, DMMCMEDIADRIVERFLASH_DMMCMEDIADRIVERFLASH, "> DMmcMediaDriverFlash::DMmcMediaDriverFlash;aMediaId=%d;iMediaId=%d", (TInt) aMediaId, (TInt) iMediaId ); sl@0: sl@0: } sl@0: sl@0: #pragma warning( default : 4355 ) sl@0: TInt DMmcMediaDriverFlash::DoCreate(TInt /*aMediaId*/) sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOCREATE_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:opn")); sl@0: sl@0: iSocket = ((DMMCSocket*)((DPBusPrimaryMedia*)iPrimaryMedia)->iSocket); sl@0: if(iSocket == NULL) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT1, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: iCardNumber = ((DPBusPrimaryMedia*)iPrimaryMedia)->iSlotNumber; sl@0: sl@0: iStack = iSocket->Stack(KStackNumber); sl@0: iCard = iStack->CardP(CardNum()); sl@0: sl@0: TMMCMachineInfo machineInfo; sl@0: Stack().MachineInfo(machineInfo); sl@0: TInt slotFlag = iCardNumber == 0 ? TMMCMachineInfo::ESlot1Internal : TMMCMachineInfo::ESlot2Internal; sl@0: iInternalSlot = machineInfo.iFlags & slotFlag; sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash::DoCreate() slotNumber %d iInternalSlot %d", iCardNumber, iInternalSlot)); sl@0: OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_SLOT, "slotNumber=%d; iInternalSlot=%d", iCardNumber, iInternalSlot); sl@0: sl@0: iSessionEndDfc.SetDfcQ(&iSocket->iDfcQ); sl@0: iDataTransferCallBackDfc.SetDfcQ(&iSocket->iDfcQ); sl@0: sl@0: // check right type of card sl@0: if ((iMediaType=iCard->MediaType())==EMultiMediaNotSupported) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT2, this, KErrNotReady ); sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: // get card characteristics sl@0: const TCSD& csd = iCard->CSD(); sl@0: iBlkLenLog2 = iCard->MaxReadBlLen(); sl@0: iBlkLen = 1 << iBlkLenLog2; sl@0: iBlkMsk = (TInt64)(iBlkLen - 1); sl@0: sl@0: SetTotalSizeInBytes(iCard->DeviceSize64()); sl@0: sl@0: // sl@0: // High capcity cards (block addressable, MMCV4.2, SD2.0) do not support partial reads sl@0: // ...some cards incorrectly report that they do, so ensure that we don't sl@0: // sl@0: iReadBlPartial = iCard->IsHighCapacity() ? EFalse : csd.ReadBlPartial(); sl@0: sl@0: // allocate and initialize session object sl@0: TInt r = AllocateSession(); sl@0: if (r!= KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT3, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: // get buffer memory from EPBUS sl@0: TUint8* buf; sl@0: TInt bufLen; sl@0: TInt minorBufLen; sl@0: Stack().BufferInfo(buf, bufLen, minorBufLen); sl@0: sl@0: iMinorBuf = buf; sl@0: sl@0: // cache buffer can use rest of blocks in buffer. Does not have to be power of 2. sl@0: iCacheBuf = iMinorBuf + minorBufLen; sl@0: sl@0: // We need to devide up the buffer space between the media drivers. sl@0: // The number of buffer sub-areas = number of physical card slots * number of media sl@0: bufLen-= minorBufLen; sl@0: DPBusPrimaryMedia* primaryMedia = (DPBusPrimaryMedia*) iPrimaryMedia; sl@0: TInt physicalCardSlots = iStack->iMaxCardsInStack; sl@0: TInt numMedia = primaryMedia->iLastMediaId - primaryMedia->iMediaId + 1; sl@0: TInt totalNumMedia = numMedia * physicalCardSlots; sl@0: sl@0: TInt mediaIndex = iMediaId - primaryMedia->iMediaId; sl@0: TInt bufIndex = (iCardNumber * numMedia) + mediaIndex; sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("physicalCardSlots %d, iCardNumber %d\n", physicalCardSlots, iCardNumber)); sl@0: OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_VARS1, "physicalCardSlots=%d; iCardNumber=%d", physicalCardSlots, iCardNumber); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("iMediaId %d numMedia %d, mediaIndex %d, totalNumMedia %d, bufIndex %d\n", sl@0: iMediaId, numMedia, mediaIndex, totalNumMedia, bufIndex)); sl@0: OstTraceExt5(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_VARS2, "iMediaId=%d; numMedia=%d; mediaIndex=%d; totalNumMedia=%d; bufIndex=%d", iMediaId, numMedia, mediaIndex, totalNumMedia, bufIndex); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("bufLen1 %08X iCacheBuf1 %08X", bufLen, iCacheBuf)); sl@0: OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_CACHEBUF1, "bufLen1=0x%08x; iCacheBuf1=0x%08x", (TUint) bufLen, (TUint) iCacheBuf); sl@0: bufLen/= totalNumMedia; sl@0: iCacheBuf+= bufIndex * bufLen; sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("bufLen2 %08X iCacheBuf2 %08X", bufLen, iCacheBuf)); sl@0: OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_CACHEBUF2, "bufLen2=0x%08x; iCacheBuf2=0x%08x", (TUint) bufLen, (TUint) iCacheBuf); sl@0: sl@0: iBlocksInBuffer = bufLen >> iBlkLenLog2; // may lose partial block sl@0: if(iSocket->SupportsDoubleBuffering()) sl@0: { sl@0: // Ensure that there's always an even number of buffered blocks when double-buffering sl@0: iBlocksInBuffer &= ~1; sl@0: __ASSERT_DEBUG(iBlocksInBuffer >= 2, Panic(EDBNotEven)); sl@0: #if defined(_DEBUG) sl@0: /** sl@0: * If Double-Buffering is enabled then the cache should not be greater than the maximum addressable range of the DMA controller, sl@0: * otherwise Double buffering will never be utilised because all transfers will fit into the cache. sl@0: */ sl@0: const TUint32 maxDbBlocks = iSocket->MaxDataTransferLength() >> iBlkLenLog2; sl@0: if (maxDbBlocks) sl@0: { sl@0: __ASSERT_DEBUG(iBlocksInBuffer <= (TInt)maxDbBlocks, Panic(EDBNotOptimal)); sl@0: } sl@0: #endif sl@0: } sl@0: sl@0: iMaxBufSize = iBlocksInBuffer << iBlkLenLog2; sl@0: sl@0: iPrWtGpLen = iCard->PreferredWriteGroupLength(); sl@0: sl@0: // check the preferred write group length is a power of two sl@0: if(iPrWtGpLen == 0 || (iPrWtGpLen & (~iPrWtGpLen + 1)) != iPrWtGpLen) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT4, this, KErrNotReady ); sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("iMaxBufSize %d iPrWtGpLen %d\n", iMaxBufSize, iPrWtGpLen)); sl@0: OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_IPRWTGPLEN1, "iMaxBufSize=%d; iPrWtGpLen1=%d", iMaxBufSize, iPrWtGpLen); sl@0: // ensure the preferred write group length is as large as possible sl@0: // so we can write to more than one write group at once sl@0: while (iPrWtGpLen < (TUint32) iMaxBufSize) sl@0: iPrWtGpLen <<= 1; sl@0: sl@0: // ensure preferred write group length is no greater than internal cache buffer sl@0: while (iPrWtGpLen > (TUint32) iMaxBufSize) sl@0: iPrWtGpLen >>= 1; sl@0: iPrWtGpMsk = TInt64(iPrWtGpLen - 1); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPrWtGpLen #2 %d\n", iPrWtGpLen)); sl@0: OstTrace1(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_IPRWTGPLEN2, "iPrWtGpLen2=%d", iPrWtGpLen); sl@0: sl@0: // allocate index for cached blocks sl@0: iCachedBlocks = KernAlloc(iBlocksInBuffer); sl@0: if (iCachedBlocks == 0) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT5, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: InvalidateCache(); sl@0: iLstUsdCchEnt = iBlocksInBuffer - 1; // use entry 0 first sl@0: sl@0: // allocate read lookup index sl@0: iGamma = KernAlloc(iBlocksInBuffer); sl@0: if (iGamma == 0) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT6, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: // get current requirements sl@0: iReadCurrentInMilliAmps = csd.MaxReadCurrentInMilliamps(); sl@0: iWriteCurrentInMilliAmps = csd.MaxWriteCurrentInMilliamps(); sl@0: sl@0: // get preferred erase information for format operations sl@0: const TInt err = iCard->GetEraseInfo(iEraseInfo); sl@0: if(err != KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT7, this, err ); sl@0: return err; sl@0: } sl@0: sl@0: iEraseUnitMsk = TInt64(iEraseInfo.iPreferredEraseUnitSize) - 1; sl@0: sl@0: // Retrieve the demand paging info from the PSL of the stack sl@0: Stack().DemandPagingInfo(iDemandPagingInfo); sl@0: sl@0: // if a password has been supplied then it is sent when the partition info is read sl@0: sl@0: // sl@0: // If this is an internal slot, then use the eMMC partition function sl@0: // sl@0: if(iInternalSlot) sl@0: { sl@0: iMmcPartitionInfo = CreateEmmcPartitionInfo(); sl@0: if(iMmcPartitionInfo == NULL) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT8, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: TInt err = iMmcPartitionInfo->Initialise(this); sl@0: if(err != KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT9, this, err ); sl@0: return err; sl@0: } sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:dtr")); sl@0: sl@0: iSessionEndDfc.Cancel(); sl@0: iDataTransferCallBackDfc.Cancel(); sl@0: sl@0: delete iSession; sl@0: Kern::Free(iCachedBlocks); sl@0: Kern::Free(iGamma); sl@0: sl@0: delete iMmcPartitionInfo; sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("AllocSession(iSessionEndCallBack); sl@0: if (iSession == NULL) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_EXIT2, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: iSession->SetStack(iStack); sl@0: iSession->SetCard(iCard); sl@0: iSession->SetDataTransferCallback(iDataTransferCallBack); sl@0: sl@0: sl@0: sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_EXIT3, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: // ---- media access ---- sl@0: sl@0: TInt DMmcMediaDriverFlash::DoRead() sl@0: // sl@0: // set up iReqStart, iReqEnd and iReqCur and launch first read. Subsequent reads sl@0: // will be launched from the callback DFC. sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOREAD_ENTRY, this ); sl@0: TInt r = CheckDevice(EMReqTypeNormalRd); sl@0: if (r != KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOREAD_EXIT1, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: const TInt64 pos(iCurrentReq->Pos()); sl@0: TUint32 length(I64LOW(iCurrentReq->Length())); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dr:0x%lx,0x%x", pos, length)); sl@0: OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DO_READ, "Position=0x%lx; Length=0x%x", (TUint) pos, (TUint) length); sl@0: __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDRInUse)); sl@0: __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDRStart)); sl@0: __ASSERT_DEBUG(iCurrentReq->Length() >= 0, Panic(EDRNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDREnd)); sl@0: sl@0: if(length > 0) sl@0: { sl@0: iReqCur = iReqStart = pos; sl@0: iReqEnd = iReqStart + length; sl@0: sl@0: TBool allDone(EFalse); sl@0: if ( ((r = ReadDataUntilCacheExhausted(&allDone)) == KErrNone) && !allDone) sl@0: { sl@0: iMedReq = EMReqRead; sl@0: iPhysStart = iReqCur & ~iBlkMsk; sl@0: __ASSERT_DEBUG(I64HIGH(iPhysStart >> KMMCardHighCapBlockSizeLog2) == 0, Panic(ELRStart)); sl@0: sl@0: iReadToEndOfCard = ( iReqEnd >= TotalSizeInBytes() ); sl@0: // Re-calculate length as some data may have been recovered from cache sl@0: length = I64LOW(iReqEnd - iReqCur); sl@0: sl@0: if (iCurrentReq->IsPhysicalAddress() && !iReadToEndOfCard && (length >= iBlkLen) ) sl@0: r = LaunchPhysRead(iReqCur, length); sl@0: else if ( (iReqEnd - iPhysStart) > iMaxBufSize && iSocket->SupportsDoubleBuffering() && !iReadToEndOfCard) sl@0: r = LaunchDBRead(); sl@0: else sl@0: r = LaunchRead(iReqCur, length); sl@0: sl@0: if (r == KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOREAD_EXIT2, this, r ); sl@0: return r; sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: #if defined(__DEMAND_PAGING__) && !defined(__WINS__) sl@0: if (DMediaPagingDevice::PageInRequest(*iCurrentReq)) sl@0: { sl@0: r = iCurrentReq->WriteToPageHandler(NULL, 0, 0); sl@0: } sl@0: else sl@0: #endif // __DEMAND_PAGING__ sl@0: { sl@0: TPtrC8 zeroDes(NULL, 0); sl@0: r = iCurrentReq->WriteRemote(&zeroDes,0); sl@0: } sl@0: } sl@0: sl@0: // error occurred or read all from cache so complete immediately sl@0: if(r == KErrNone) sl@0: r = KErrCompletion; sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Pos(), (TUint) I64LOW(iCurrentReq->Length())); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lr:0x%lx,0x%x", aStart, aLength)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELRStart)); sl@0: __ASSERT_DEBUG(aLength > 0, Panic(ELRNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELREnd)); sl@0: __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ELRCached)); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: iDoPhysicalAddress = EFalse; sl@0: iDoDoubleBuffer = EFalse; sl@0: iSecondBuffer = EFalse; sl@0: sl@0: // sl@0: // if this read goes up to the end of the card then use only sl@0: // single sector reads to avoid CMD12 timing problems sl@0: // sl@0: const TUint32 bufSize(iReadToEndOfCard ? iBlkLen : iMaxBufSize); sl@0: sl@0: iPhysEnd = (UMin(iReqEnd, iPhysStart + bufSize) + iBlkMsk) & ~iBlkMsk; sl@0: sl@0: TUint32 physLen(I64LOW(iPhysEnd - iPhysStart)); sl@0: sl@0: __ASSERT_DEBUG(I64HIGH(iPhysEnd - iPhysStart) == 0, Panic(ELREnd)); sl@0: sl@0: // partial reads must be within a single physical block sl@0: if (iReadBlPartial && physLen == iBlkLen && aLength <= (iBlkLen >> 1)) sl@0: { sl@0: // sl@0: // Note : Partial reads are not supported for large block devices sl@0: // (MMCV4.2 and SD2.0 high capacity cards) sl@0: // sl@0: __ASSERT_DEBUG(I64HIGH(aStart) == 0, Panic(ELRStart)); sl@0: __ASSERT_DEBUG(I64HIGH(aStart + aLength) == 0, Panic(ELREnd)); sl@0: sl@0: iIntBuf = iMinorBuf; sl@0: Stack().AdjustPartialRead(iCard, I64LOW(aStart), I64LOW(aStart + aLength), (TUint32*)&iPhysStart, (TUint32*)&iPhysEnd); sl@0: iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, physLen >> KMMCardHighCapBlockSizeLog2); sl@0: } sl@0: else sl@0: { sl@0: iIntBuf = ReserveReadBlocks(iPhysStart, iPhysEnd, &physLen); sl@0: sl@0: // EPBUSM automatically uses CMD17 instead of CMD18 for single block reads sl@0: iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, physLen >> KMMCardHighCapBlockSizeLog2); sl@0: sl@0: // Update Physical end point as less may have been required due to additional blocks found in cache during ReserveReadBlocks sl@0: iPhysEnd = iPhysStart + physLen; sl@0: } sl@0: sl@0: TInt r = EngageAndSetReadRequest(EMReqRead); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:ldbr:0x%lx,0x%x", iReqCur, I64LOW(iReqEnd - iReqCur))); sl@0: OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHDBREAD, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > iReqCur, Panic(ELRStart)); sl@0: __ASSERT_DEBUG(I64LOW(iReqEnd - iReqCur) > 0, Panic(ELRNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= iReqEnd, Panic(ELREnd)); sl@0: __ASSERT_CACHE(GetCachedBlock(iReqCur & ~iBlkMsk) == 0, Panic(ELRCached)); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: iDoDoubleBuffer = ETrue; sl@0: iDoPhysicalAddress = EFalse; sl@0: sl@0: iDbEnd = iReqEnd; sl@0: const TUint32 maxDbLength = iSocket->MaxDataTransferLength(); sl@0: sl@0: if(maxDbLength) sl@0: { sl@0: // sl@0: // If the PSL specifies a limit on the maximum size of a data transfer, then truncate the request... sl@0: // sl@0: iDbEnd = UMin(iDbEnd, iPhysStart + maxDbLength); sl@0: } sl@0: sl@0: iDbEnd = (iDbEnd + iBlkMsk) & ~iBlkMsk; sl@0: sl@0: const TUint32 doubleBufferSize = iMaxBufSize >> 1; sl@0: iPhysEnd = (iReqCur + doubleBufferSize) & ~iBlkMsk; // The end of the first double-buffered transfer sl@0: sl@0: // sl@0: // If we're double-buffering, then the entire cache will be re-used sl@0: // continuously. Rather than continually reserve blocks during each sl@0: // transfer we calculate the blocks that will be present after all sl@0: // transfers have completed. sl@0: // @see DoSessionEndDfc() sl@0: // sl@0: InvalidateCache(); sl@0: iIntBuf = iCacheBuf; sl@0: sl@0: iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW(iDbEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2); sl@0: sl@0: iSession->EnableDoubleBuffering(doubleBufferSize >> KDiskSectorShift); sl@0: sl@0: // ...and switch to the 'second' buffer, which will be populated in the sl@0: // data transfer callback in parallel with hardware transfer of the first. sl@0: iSecondBuffer = ETrue; sl@0: sl@0: TInt r = EngageAndSetReadRequest(EMReqRead); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:physr:0x%lx,0x%x", aStart, aLength)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELRStart)); sl@0: __ASSERT_DEBUG(aLength > 0, Panic(ELRNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELREnd)); sl@0: __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ELRCached)); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: TInt r(KErrNone); sl@0: sl@0: iDoPhysicalAddress = ETrue; sl@0: iDoDoubleBuffer = EFalse; sl@0: sl@0: // Local Media Subsystem ensures DMA Addressable range not exceeded. sl@0: // @see LocDrv::RegisterDmaDevice() sl@0: iPhysEnd = (iReqEnd + iBlkMsk) & ~iBlkMsk; sl@0: sl@0: iRdROB = 0; sl@0: iFragOfset = iIPCLen = iNxtIPCLen = iBufOfset = 0; sl@0: sl@0: // Determine if start/end are block aligned sl@0: // physical memory can only read the exact amount, not more! sl@0: const TBool firstPartial( (aStart & iBlkMsk) != 0); sl@0: sl@0: TPhysAddr physAddr(0); sl@0: TInt physLength(0); sl@0: TUint32 physLen(I64LOW(iPhysEnd - iPhysStart)); sl@0: sl@0: if (firstPartial) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:physr:FirstPartial")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCH_PHYSREAD_FP, "FirstPartial"); sl@0: // first index does not start on block boundary sl@0: // iIntBuf linear address is used for IPC within DoReadDataTransferCallBack() sl@0: iRdROB |= KIPCWrite; sl@0: sl@0: iIntBuf = ReserveReadBlocks(iPhysStart, iPhysStart+iBlkLen,(TUint32*)&physLength); sl@0: #if !defined(__WINS__) sl@0: physAddr = Epoc::LinearToPhysical((TLinAddr)iIntBuf); sl@0: #else sl@0: physAddr = (TPhysAddr)iIntBuf; sl@0: #endif sl@0: // Set SecondBuffer flag to indicate IPC cannot be done on next callback sl@0: iSecondBuffer = ETrue; sl@0: iBufOfset = I64LOW(iReqStart - iPhysStart); sl@0: //iReqCur already set in DoRead; sl@0: iFragOfset = iNxtIPCLen = physLength - iBufOfset; sl@0: } sl@0: else sl@0: { sl@0: // Determine offset from start due to data possibly recovered from local cache sl@0: iFragOfset = I64LOW(aStart - iReqStart); sl@0: r = PrepareFirstPhysicalFragment(physAddr, physLength, aLength); sl@0: sl@0: // No use for secondBuffer yet... sl@0: iSecondBuffer = EFalse; sl@0: } sl@0: sl@0: if(r == KErrNone) sl@0: { sl@0: iDbEnd = iPhysEnd; sl@0: iPhysEnd = iPhysStart + physLength; sl@0: sl@0: if ((TUint32)physLength > physLen) physLength = physLen; // more memory in chunk than required sl@0: sl@0: iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), (TUint8*)physAddr, physLen >> KMMCardHighCapBlockSizeLog2); sl@0: sl@0: iSession->Command().iFlags|= KMMCCmdFlagPhysAddr; sl@0: iSession->EnableDoubleBuffering(physLength >> KDiskSectorShift); sl@0: sl@0: r = EngageAndSetReadRequest(EMReqRead); sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Pos(); sl@0: const TUint32 length = I64LOW(iCurrentReq->Length()); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dw:0x%lx,0x%x", pos, length)); sl@0: OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOWRITE, "position=0x%lx; length=0x%x", (TUint) pos, (TUint) length); sl@0: __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDWInUse)); sl@0: __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDWStart)); sl@0: __ASSERT_DEBUG(length > 0, Panic(EDWNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDWEnd)); sl@0: sl@0: iReqCur = iReqStart = pos; sl@0: iReqEnd = iReqStart + length; sl@0: sl@0: // iWtRBM is zero on construction because CBase-derived, and cleared at end sl@0: // of successful writes. If a write does not complete successfully, it may sl@0: // be left in non-zero state. sl@0: iWtRBM = 0; sl@0: sl@0: iSecondBuffer = EFalse; sl@0: iDoLastRMW = EFalse; sl@0: iDoDoubleBuffer= EFalse; sl@0: iDoPhysicalAddress = EFalse; sl@0: sl@0: const TInt r = LaunchWrite(iReqStart, length, EMReqWrite); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Pos(); sl@0: const TUint32 length = I64LOW(iCurrentReq->Length()); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:df:0x%lx,0x%x", pos, length)); sl@0: OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOFORMAT, "position=0x%lx; length=0x%x", (TUint) pos, (TUint) length); sl@0: __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDFInUse)); sl@0: __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDFStart)); sl@0: __ASSERT_DEBUG(length > 0, Panic(EDFNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDFEnd)); sl@0: sl@0: iReqCur = iReqStart = pos & ~iBlkMsk; sl@0: iReqEnd = (iReqStart + length + iBlkMsk) & ~iBlkMsk; sl@0: sl@0: // the cache isn't maintained during a format operation to avoid redundantly sl@0: // writing 0xff to memory (the blocks won't be re-used.) sl@0: InvalidateCache(); sl@0: sl@0: // create an MBR after the first format step (or second if misaligned) sl@0: sl@0: if (iInternalSlot) sl@0: { sl@0: iCreateMbr = EFalse; sl@0: } sl@0: else sl@0: { sl@0: if (iReqStart == (TInt64(iHiddenSectors) << KDiskSectorShift) && CreateMBRAfterFormat(iCard)) sl@0: iCreateMbr = ETrue; sl@0: } sl@0: sl@0: const TInt r = LaunchFormat(iReqStart, I64LOW(iReqEnd - iReqStart)); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lf:0x%lx,0x%x", aStart, aLength)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELFStart)); sl@0: __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(ELWFmtStAlign)); sl@0: __ASSERT_DEBUG(aLength > 0, Panic(ELFNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELFEnd)); sl@0: __ASSERT_DEBUG((aLength & iBlkMsk) == 0, Panic(ELWFmtEndAlign)); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: TInt r; sl@0: sl@0: if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone) sl@0: { sl@0: iPhysStart = aStart & ~iBlkMsk; sl@0: sl@0: // formats are always block-aligned, and the buffer is initialized to 0xff sl@0: // Check whether erase commands are supported by this card sl@0: if (iCard->CSD().CCC() & KMMCCmdClassErase) sl@0: { sl@0: // Determine the erase end point for the next command. We don't erase past the preferred erase unit sl@0: // size. Therefore, check which is lower, the preferred erase unit size or the end of the requested range. sl@0: TInt64 prefEraseUnitEnd = (iPhysStart + iEraseInfo.iPreferredEraseUnitSize) & ~iEraseUnitMsk; sl@0: iPhysEnd = UMin(prefEraseUnitEnd, aStart + aLength); sl@0: sl@0: const TUint32 minEraseSectorSize=iEraseInfo.iMinEraseSectorSize; sl@0: const TInt64 minEraseSecMsk = TInt64(minEraseSectorSize-1); sl@0: sl@0: // If erase start point doesn't lie on a min. erase unit boundary, then truncate the erase endpoint to sl@0: // the next min. erase unit boundary (assuming requested range allows this) sl@0: if ((iPhysStart & minEraseSecMsk)!=0) sl@0: { sl@0: prefEraseUnitEnd=(iPhysStart+minEraseSectorSize) & ~minEraseSecMsk; sl@0: iPhysEnd=UMin(prefEraseUnitEnd,iPhysEnd); sl@0: } sl@0: sl@0: // Otherwise, if calculated erase end point doesn't lie on a min. erase unit boundary, but is at least one sl@0: // min. erase unit beyond the erase start point then move erase endpoint back to last min. erase unit boundary sl@0: else if ((iPhysEnd & minEraseSecMsk)!=0 && (iPhysEnd & ~minEraseSecMsk)>iPhysStart) sl@0: { sl@0: iPhysEnd&=(~minEraseSecMsk); sl@0: } sl@0: sl@0: // Now, if the erase start/end points are aligned to a min. erase unit boundary, we can use an erase cmd. sl@0: if ((iPhysStart & minEraseSecMsk) == 0 && (iPhysEnd & minEraseSecMsk) == 0) sl@0: { sl@0: // Aligned erase sl@0: // Check that erase commands are supported prior to issuing an erase command sl@0: if(iEraseInfo.EraseGroupCmdsSupported()) sl@0: { sl@0: iSession->SetupCIMEraseMGroup(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), sl@0: I64LOW((iPhysEnd-iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD35/36/38 (Erase Group) sl@0: } sl@0: else sl@0: { sl@0: iSession->SetupCIMEraseMSector(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), sl@0: I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD32/33/38 (Erase Sector) sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // Misaligned erase - use multi-block write. However, first - check write length doesn't exceed buffer size. sl@0: if ((iPhysEnd-iPhysStart)>(TUint32)iMaxBufSize) sl@0: { sl@0: iPhysEnd=(iPhysStart+iMaxBufSize); sl@0: } sl@0: sl@0: __ASSERT_DEBUG((iPhysEnd - iPhysStart) > 0, Panic(ELWLength)); sl@0: const TUint32 writeLen = I64LOW(iPhysEnd - iPhysStart); sl@0: memset (iCacheBuf, 0x00, writeLen); sl@0: iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // Write to end of current write group, or end of request range, whichever is lower sl@0: const TInt64 prefEraseUnitEnd = (iPhysStart + iPrWtGpLen) & ~iPrWtGpMsk; sl@0: iPhysEnd = Min(prefEraseUnitEnd, aStart + aLength); sl@0: sl@0: __ASSERT_DEBUG((iPhysEnd - iPhysStart) > 0, Panic(ELWLength)); sl@0: const TUint32 writeLen = I64LOW(iPhysEnd - iPhysStart); sl@0: memset (iCacheBuf, 0x00, writeLen); sl@0: iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2); sl@0: } sl@0: sl@0: r = EngageAndSetWriteRequest(EMReqFormat); sl@0: } sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHFORMAT_EXIT, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: sl@0: TInt DMmcMediaDriverFlash::LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq) sl@0: // sl@0: // starts writes from DoWrite(), DoFormat() and the session end DFC. This function does not sl@0: // maintain the iReq* instance variables. It sets iIntBuf, iPhysStart and iPhysEnd. sl@0: // sl@0: { sl@0: OstTraceExt4(TRACE_FLOW, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_ENTRY, "DMmcMediaDriverFlash::LaunchWrite;aStart=%Ld;aLength=%x;aMedReq=%d;this=%x", aStart, (TUint) aLength, (TInt) aMedReq, (TUint) this); sl@0: OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("\n>mmd:lw:0x%lx,%d,%d", aStart, aLength, aMedReq)); sl@0: __ASSERT_DEBUG(aMedReq == EMReqWrite || aMedReq == EMReqFormat, Panic(ELWRequest)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELWStart)); sl@0: __ASSERT_DEBUG(!(aMedReq == EMReqFormat) || (aStart & iBlkMsk) == 0, Panic(ELWFmtStAlign)); sl@0: __ASSERT_DEBUG(aLength > 0, Panic(ELWNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELWEnd)); sl@0: __ASSERT_DEBUG(!(aMedReq == EMReqFormat) || (aLength & iBlkMsk) == 0, Panic(ELWFmtEndAlign)); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: TInt r; sl@0: sl@0: if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone) sl@0: { sl@0: iPhysStart = aStart & ~iBlkMsk; sl@0: sl@0: // PSL MUST support double-buffering for DMA requests sl@0: // first write, or have just completed previous write sl@0: if (iWtRBM == 0) sl@0: { sl@0: if(iDoDoubleBuffer == EFalse) sl@0: { sl@0: // sl@0: // Can we use double-buffering for this request? sl@0: // sl@0: // - Only if PSL supports double buffering and the request length sl@0: // is greater than the maximum PSL buffer size. sl@0: // sl@0: iDoPhysicalAddress = iCurrentReq->IsPhysicalAddress(); sl@0: sl@0: TInt64 medEnd = aStart + aLength; sl@0: sl@0: TInt64 maxPslEnd = medEnd; sl@0: const TUint32 maxDbLength = iSocket->MaxDataTransferLength(); sl@0: sl@0: if(maxDbLength) sl@0: { sl@0: // sl@0: // If the PSL specifies a limit on the maximum size of a data transfer, then truncate the request... sl@0: // sl@0: maxPslEnd = UMin(medEnd, iPhysStart + maxDbLength); sl@0: } sl@0: sl@0: iPhysEnd = (maxPslEnd + iBlkMsk) & ~iBlkMsk; sl@0: sl@0: if (iDoPhysicalAddress) sl@0: { sl@0: iDoDoubleBuffer = EFalse; sl@0: iIntBuf = ReserveWriteBlocks(aStart, medEnd, &iWtRBM); sl@0: iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk; sl@0: } sl@0: sl@0: if (!iDoPhysicalAddress) sl@0: { sl@0: iDoDoubleBuffer = iSocket->SupportsDoubleBuffering() && ((iPhysEnd - iPhysStart) > iMaxBufSize); sl@0: if(iDoDoubleBuffer) sl@0: { sl@0: // sl@0: // Conditions for double-buffering are met. Set up the size of the first sl@0: // transfer to half the size of the block cache. sl@0: // sl@0: // Note that we don't bother to align to write groups here, as the entire sl@0: // request will be processed under one multi-block command so there's no sl@0: // danger of forcing the card into RMW cycles as would be the case when sl@0: // issuing multiple misaligned commands. sl@0: // sl@0: iDbEnd = maxPslEnd; // The end of the complete double-buffered transfer sl@0: iPhysEnd = (iPhysStart + (iMaxBufSize >> 1) + iBlkMsk) &~ iBlkMsk; // The end of the first double-buffered transfer sl@0: __ASSERT_DEBUG(iPhysEnd - iPhysStart <= (iMaxBufSize >> 1), Panic(ELWLength)); sl@0: sl@0: // sl@0: // Now reserve write blocks from the buffer cache. When double-buffering, sl@0: // write blocks are only really reserved during the last transfer to avoid sl@0: // continuously updating the cache indexes. Since the block cache is sl@0: // continuously recycled, the following call shall invalidate the cache sl@0: // and inform us as to whether we need to perform an RMW operation for sl@0: // the first and last blocks prior to initiating data transfer. sl@0: // sl@0: iIntBuf = ReserveWriteBlocks(aStart, iDbEnd, &iWtRBM); sl@0: } sl@0: else sl@0: { sl@0: if ( (iPhysEnd - iPhysStart) > iMaxBufSize) sl@0: { sl@0: // sl@0: // reserve buffers to end of first write group, or end of request range, sl@0: // whichever is lower. Note that if the range already exists in the buffer, sl@0: // e.g. because of a previous RBM, the same range will be returned. This sl@0: // means that iWtRBM can be set to zero in the callback DFC, and this code sl@0: // will retrieve the reserved range. sl@0: // sl@0: const TInt64 wtGpEnd = (iPhysStart + iPrWtGpLen) & ~iPrWtGpMsk; sl@0: medEnd = UMin(wtGpEnd, aStart + aLength); sl@0: iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk; sl@0: } sl@0: sl@0: iIntBuf = ReserveWriteBlocks(aStart, medEnd, &iWtRBM); sl@0: } sl@0: } //if (!iDoPhysicalAddress) sl@0: } //if(iDoDoubleBuffer == EFalse) sl@0: } //if (iWtRBM == 0) sl@0: sl@0: if (iWtRBM & KWtRBMFst) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw: read-before-modify required on first block")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_RBMF, "Read-before-modify required on first block"); sl@0: if (iDoPhysicalAddress) sl@0: iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iMinorBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2); sl@0: else sl@0: iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2); sl@0: r = EngageAndSetReadRequest(aMedReq); sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT1, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: else if (iWtRBM & KWtRBMLst) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw: read-before-modify required on last block")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_RBML, "Read-before-modify required on last block"); sl@0: if(iDoDoubleBuffer || iDoPhysicalAddress) sl@0: { sl@0: // sl@0: // When double-buffering, the result of the RMW-read operation shall be stored sl@0: // in the minor buffer, otherwise the data would be overwritten before the last sl@0: // data transfer takes place. sl@0: // sl@0: 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) sl@0: if (iDoDoubleBuffer) sl@0: iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iMinorBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2); sl@0: else sl@0: iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iCacheBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2); sl@0: } sl@0: else sl@0: { sl@0: // sl@0: // If not double-buffering, we can read the RMW data of the last block directly sl@0: // into the block cache as we know that the data transfer will fit entirely sl@0: // within the cache.. sl@0: // sl@0: const TInt64 lastBlock = iPhysEnd - iBlkLen; // start posn in media to read from sl@0: iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iIntBuf + (lastBlock - iPhysStart), iBlkLen >> KMMCardHighCapBlockSizeLog2); sl@0: } sl@0: sl@0: // Kick off the RMW-read operation for the last block... sl@0: r = EngageAndSetReadRequest(aMedReq); sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT2, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: if (iWtRBM & KWtMinFst) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:Phys write-first-block-only")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_FBO, "Write first block only"); sl@0: //Overwrite first block with the new data sl@0: TInt32 tlen = I64LOW(aStart & iBlkMsk); sl@0: TInt32 wlen = UMin(I64LOW((iBlkMsk+1) - tlen), aLength); sl@0: sl@0: const TInt64 usrOfst = (aStart - iReqStart); sl@0: TPtr8 tgt(&iMinorBuf[tlen], I64LOW(wlen)); sl@0: sl@0: if ( (r = iCurrentReq->ReadRemote(&tgt,I64LOW(usrOfst))) != KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT3, this, r ); sl@0: return r; sl@0: } sl@0: } sl@0: sl@0: if (iWtRBM & KWtMinLst) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:Phys write-last-block-only")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_LBO, "Write last block only"); sl@0: iWtRBM &= ~KWtMinLst; sl@0: //Overwrite last block with the new data sl@0: const TInt64 medEnds = aStart + aLength; sl@0: TInt64 tlen = medEnds & iBlkMsk; sl@0: sl@0: const TInt64 usrOfst = (aStart - iReqStart); sl@0: TPtr8 tgt(iCacheBuf, I64LOW(tlen)); sl@0: sl@0: if ( (r = iCurrentReq->ReadRemote(&tgt,I64LOW(usrOfst+aLength-tlen))) !=KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT4, this, r ); sl@0: return r; sl@0: } sl@0: } sl@0: sl@0: // no reads required - read data from user buffer and launch write sl@0: const TInt64 usrOfst = (aStart - iReqStart); sl@0: const TInt64 bufOfst = aStart - iPhysStart; // offset into first sector, not whole buffer sl@0: const TInt64 len = UMin(aStart + aLength, iPhysEnd) - iReqCur; sl@0: __ASSERT_DEBUG(len > 0, Panic(ELWLength)); sl@0: __ASSERT_DEBUG(I64HIGH(usrOfst) == 0, Panic(ELWLength)); sl@0: sl@0: if (iDoPhysicalAddress) sl@0: { sl@0: TPhysAddr physAddr = 0; sl@0: TInt physLength = 0; sl@0: TUint32 physLen = I64LOW(iPhysEnd - iPhysStart); sl@0: sl@0: if (iWtRBM & KWtMinFst) sl@0: { sl@0: #if !defined(__WINS__) sl@0: physAddr = Epoc::LinearToPhysical((TLinAddr)iMinorBuf); sl@0: #else sl@0: physAddr = (TPhysAddr)iMinorBuf; sl@0: #endif sl@0: physLength = iBlkLen; sl@0: iBufOfset = I64LOW(iReqStart - iPhysStart); sl@0: //iReqCur already set in DoWrite sl@0: iFragOfset = iIPCLen = iBlkLen - iBufOfset; sl@0: iWtRBM &= ~KWtMinFst; sl@0: } sl@0: else sl@0: { sl@0: iFragOfset = I64LOW(usrOfst); sl@0: sl@0: r = PrepareFirstPhysicalFragment(physAddr, physLength, aLength); sl@0: } sl@0: sl@0: if (r == KErrNone) sl@0: { sl@0: iDbEnd = iPhysEnd; sl@0: iPhysEnd = iPhysStart+physLength; sl@0: sl@0: if ((TUint32)physLength > physLen) physLength = physLen; // more memory in fragment than required! sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_PHYSICAL, "Physical write request" ); sl@0: iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), (TUint8*) physAddr, physLen >> KMMCardHighCapBlockSizeLog2); sl@0: iSession->Command().iFlags|= KMMCCmdFlagPhysAddr; sl@0: iSession->EnableDoubleBuffering(physLength >> KDiskSectorShift); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); sl@0: } sl@0: else sl@0: { sl@0: // sl@0: // When double-buffering, set up the data transfer command to the entire sl@0: // request range. and flag the session to enable double-buffering (as well sl@0: // as specifying the length of each double-buffered transfer as calculated sl@0: // in 'len' above). This is performed only once - the double-buffering sl@0: // is subsequently handled within the DoDataTransferCallback function. sl@0: // sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_DB, "Double-buffered write request" ); sl@0: iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW((((iDbEnd + iBlkMsk) & ~iBlkMsk) - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); sl@0: iSession->EnableDoubleBuffering(I64LOW((len + iBlkMsk) & ~iBlkMsk) >> KDiskSectorShift); sl@0: sl@0: // ...and switch to the 'second' buffer, which will be populated in the sl@0: // data transfer callback in parallel with hardware transfer of the first. sl@0: iSecondBuffer = ETrue; sl@0: } sl@0: } sl@0: } sl@0: sl@0: //Reliable Write only supported by v4.3+ MMC media sl@0: if (iCard->ExtendedCSD().ExtendedCSDRev() >= 3) sl@0: { sl@0: // One request, i.e. not end of previous DB request sl@0: // 512 Bytes long when sector aligned sl@0: if ( ( I64LOW(iPhysEnd - iPhysStart) == iBlkLen) && ((iReqStart & ~iBlkMsk) == iPhysStart) ) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:AtomicWrite")); sl@0: iSession->Command().iFlags|= KMMCCmdFlagReliableWrite; sl@0: } sl@0: } sl@0: sl@0: // Engage the data transfer session... sl@0: r = EngageAndSetWriteRequest(aMedReq); sl@0: } // if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone) sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:rpi")); sl@0: __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(ERPIInUse)); sl@0: sl@0: iPartitionInfo = &anInfo; sl@0: sl@0: if(iMmcPartitionInfo) sl@0: { sl@0: // If this is an embedded device, use the custom formatting function: sl@0: TInt r = iMmcPartitionInfo->PartitionInfo(*iPartitionInfo, iSessionEndCallBack); sl@0: sl@0: iHiddenSectors = 0; // Not used for internal media sl@0: sl@0: if (KErrNone == r) sl@0: iMedReq = EMReqEMMCPtnInfo; sl@0: sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT1, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: // Assume MBR will be present or is not required sl@0: iMbrMissing = EFalse; sl@0: sl@0: // If media driver is persistent (see EMediaDriverPersistent), sl@0: // the card may have changed since last power down, so reset CID sl@0: iSession->SetCard(iCard); sl@0: sl@0: TInt r = LaunchRPIRead(); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lru:%d,%d", iCard->IsReady(), iCard->IsLocked())); sl@0: OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHRPIUNLOCK_ICARD, "iCard->IsReady=%d; iCard->IsLocked=%d", iCard->IsReady(), iCard->IsLocked()); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: TInt r = KErrNone; sl@0: sl@0: // CMD42 is an adtc, so check state in same way as for write sl@0: if ((r = CheckDevice(EMReqTypeUnlockPswd)) == KErrNone) sl@0: { sl@0: r = Stack().MMCSocket()->PrepareStore(CardNum(), DLocalDrive::EPasswordUnlock, aPasswordData); sl@0: sl@0: if (r == KErrNone) sl@0: { sl@0: TMediaPassword curPwd; sl@0: sl@0: curPwd = *aPasswordData.iOldPasswd; sl@0: sl@0: TInt curPwdLen = curPwd.Length(); sl@0: TInt blockLen = 2 + curPwdLen; sl@0: sl@0: TPtr8 pbuf(&iMinorBuf[0], 2, blockLen); sl@0: pbuf[0] = 0; // LOCK_UNLOCK = 0; SET_PWD = 0 sl@0: pbuf[1] = static_cast(curPwdLen); sl@0: pbuf.Append(curPwd); sl@0: iSession->SetupCIMLockUnlock(blockLen, iMinorBuf); sl@0: sl@0: r = EngageAndSetWriteRequest(EMReqUpdatePtnInfo); sl@0: } sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lrr"))); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: // the partition information is read before any other area is read from / sl@0: // written to, and so does not need to maintain cache coherence. Therefore sl@0: // it can safely use the minor buffer. sl@0: sl@0: TInt r; sl@0: if ((r = CheckDevice(EMReqTypeNormalRd)) == KErrNone) sl@0: { sl@0: iIntBuf = iMinorBuf; sl@0: iSession->SetupCIMReadBlock(0, iIntBuf); // aBlocks = 1 sl@0: r = EngageAndSetReadRequest(EMReqPtnInfo); sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lre:%d,%d", iCard->IsReady(), iCard->IsLocked())); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: TInt r = KErrNone; sl@0: sl@0: // CMD42 is an adtc, so check state in same way as for write sl@0: if ((r = CheckDevice(EMReqTypeUnlockPswd)) == KErrNone) sl@0: { sl@0: if(iCard->IsWriteProtected()) sl@0: { sl@0: r = KErrAccessDenied; sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:df:EMReqForceErase")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHRPIERASE_FORCE_ERASE, "Force erase"); sl@0: iMinorBuf[0] = KMMCLockUnlockErase; sl@0: iSession->SetupCIMLockUnlock(1, iMinorBuf); sl@0: r = EngageAndSetWriteRequest(EMReqForceErase); sl@0: } sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionCount=0; sl@0: TInt defaultPartitionNumber=-1; sl@0: TMBRPartitionEntry* pe; sl@0: const TUint KMBRFirstPartitionOffsetAligned = KMBRFirstPartitionOffset & ~3; sl@0: TInt i; sl@0: sl@0: // Read of the first sector successful so check for a Master Boot Record sl@0: if (*(TUint16*)(&iIntBuf[KMBRSignatureOffset])!=0xAA55) sl@0: goto mbr_done; sl@0: sl@0: __ASSERT_COMPILE(KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry) <= KMBRSignatureOffset); sl@0: sl@0: memmove(&iIntBuf[0], &iIntBuf[2], sl@0: KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry)); sl@0: sl@0: sl@0: for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]); sl@0: pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++) sl@0: { sl@0: if (pe->IsDefaultBootPartition()) sl@0: { sl@0: SetPartitionEntry(&iPartitionInfo->iEntry[0],pe->iFirstSector,pe->iNumSectors); sl@0: defaultPartitionNumber=i; sl@0: partitionCount++; sl@0: break; sl@0: } sl@0: } sl@0: sl@0: // Now add any other partitions sl@0: for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]); sl@0: pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++) sl@0: { sl@0: TBool validPartition = ETrue; // assume partition valid sl@0: sl@0: if (defaultPartitionNumber==i) sl@0: { sl@0: // Already sorted sl@0: } sl@0: sl@0: // FAT partition ? sl@0: else if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition() || pe->IsValidExFATPartition()) sl@0: { sl@0: SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); sl@0: __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: FAT partition found at sector #%u", pe->iFirstSector)); sl@0: OstTrace1(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_FS,"FAT partition found at sector #%u", pe->iFirstSector); sl@0: partitionCount++; sl@0: } sl@0: else sl@0: { sl@0: validPartition = EFalse; sl@0: } sl@0: sl@0: if (validPartition && partitionCount == 1) sl@0: iHiddenSectors = pe->iFirstSector; sl@0: sl@0: } sl@0: sl@0: // Check the validity of the partition address boundaries sl@0: // If there is any sl@0: if(partitionCount > 0) sl@0: { sl@0: const TInt64 deviceSize = iCard->DeviceSize64(); sl@0: TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1]; sl@0: // Check that the card address space boundary is not exceeded by the last partition sl@0: // In case of only 1 partition in the media check also it sl@0: if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT1, "MBR partition exceeds card memory space" ); sl@0: // Adjust the partition length to card address boundary sl@0: part.iPartitionLen = (deviceSize - part.iPartitionBaseAddr); sl@0: sl@0: // Check that the base address contained valid information sl@0: if(part.iPartitionLen <= 0) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Invalid base address")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT2, "Invalid base address" ); sl@0: // Invalid MBR - assume the boot sector is in the first sector sl@0: defaultPartitionNumber =-1; sl@0: partitionCount=0; sl@0: } sl@0: } sl@0: // More than one partition. Go through all of them sl@0: if (partitionCount > 0) sl@0: { sl@0: for(i=partitionCount-1; i>0; i--) sl@0: { sl@0: const TPartitionEntry& curr = iPartitionInfo->iEntry[i]; sl@0: TPartitionEntry& prev = iPartitionInfo->iEntry[i-1]; sl@0: // Check if partitions overlap sl@0: if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen)) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Overlapping partitions")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT3, "Overlapping partitions" ); sl@0: // Adjust the partition length to not overlap the next partition sl@0: prev.iPartitionLen = (curr.iPartitionBaseAddr - prev.iPartitionBaseAddr); sl@0: sl@0: // Check that the base address contained valid information sl@0: if(prev.iPartitionLen <= 0) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Invalid base address")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT4, "Invalid base address" ); sl@0: // Invalid MBR - assume the boot sector is in the first sector sl@0: defaultPartitionNumber=(-1); sl@0: partitionCount=0; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: mbr_done: sl@0: if (defaultPartitionNumber==(-1) && partitionCount==0) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc:PartitionInfo no MBR")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_MBRDONE1, "No MBR" ); sl@0: if (MBRMandatory(iCard)) sl@0: { sl@0: // If the MBR is missing AND is required, we present a default partition entry to the local sl@0: // media subsystem, which will be updated when the media is finally formatted sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("MBR mandatory, defining space for MBR + default partition")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_MBRDONE2, "MBR mandatory, defining space for MBR + default partition" ); sl@0: iMbrMissing = ETrue; sl@0: TInt r = CreateDefaultPartition(); sl@0: if (r != KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_EXIT1, this, r ); sl@0: return r; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // Assume it has no MBR, and the Boot Sector is in the 1st sector sl@0: SetPartitionEntry(&iPartitionInfo->iEntry[0],0,I64LOW(iCard->DeviceSize64()>>KDiskSectorShift)); sl@0: iHiddenSectors=0; sl@0: } sl@0: partitionCount=1; sl@0: } sl@0: sl@0: iPartitionInfo->iPartitionCount=partitionCount; sl@0: iPartitionInfo->iMediaSizeInBytes=TotalSizeInBytes(); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionCount)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition1 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[0].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[0].iPartitionLen))); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition2 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[1].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[1].iPartitionLen))); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition3 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[2].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[2].iPartitionLen))); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition4 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[3].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[3].iPartitionLen))); sl@0: 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)); sl@0: 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)); sl@0: sl@0: #ifdef _DEBUG sl@0: TMBRPartitionEntry cPe; sl@0: if(GetDefaultPartitionInfo(cPe) == KErrNone) sl@0: { sl@0: pe = (TMBRPartitionEntry*)(&iIntBuf[0]); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------")); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- Partition Entry Validation/Comparison --")); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------")); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iX86BootIndicator [%02x:%02x] %c -", pe->iX86BootIndicator, cPe.iX86BootIndicator, pe->iX86BootIndicator == cPe.iX86BootIndicator ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartHead [%02x:%02x] %c -", pe->iStartHead, cPe.iStartHead, pe->iStartHead == cPe.iStartHead ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartSector [%02x:%02x] %c -", pe->iStartSector, cPe.iStartSector, pe->iStartSector == cPe.iStartSector ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartCylinder [%02x:%02x] %c -", pe->iStartCylinder, cPe.iStartCylinder, pe->iStartCylinder == cPe.iStartCylinder ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iPartitionType [%02x:%02x] %c -", pe->iPartitionType, cPe.iPartitionType, pe->iPartitionType == cPe.iPartitionType ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndHead [%02x:%02x] %c -", pe->iEndHead, cPe.iEndHead, pe->iEndHead == cPe.iEndHead ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndSector [%02x:%02x] %c -", pe->iEndSector, cPe.iEndSector, pe->iEndSector == cPe.iEndSector ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndCylinder [%02x:%02x] %c -", pe->iEndCylinder, cPe.iEndCylinder, pe->iEndCylinder == cPe.iEndCylinder ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iFirstSector [%08x:%08x] %c -", pe->iFirstSector, cPe.iFirstSector, pe->iFirstSector == cPe.iFirstSector ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iNumSectors [%08x:%08x] %c -", pe->iNumSectors, cPe.iNumSectors, pe->iNumSectors == cPe.iNumSectors ? ' ' : 'X')); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------")); sl@0: } sl@0: #endif sl@0: sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_EXIT2, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DMmcMediaDriverFlash::WritePartitionInfo() sl@0: /** sl@0: Write the default partition table to freshly formatted media sl@0: @return Standard Symbian OS Error Code sl@0: */ sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:wpi")); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: TMBRPartitionEntry partitionEntry; sl@0: TInt err = GetDefaultPartitionInfo(partitionEntry); sl@0: if(err == KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:MBR/Partition Table")); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Boot ID : %02xh", partitionEntry.iX86BootIndicator)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Head : %02xh", partitionEntry.iStartHead)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Sector : %02xh", partitionEntry.iStartSector)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Cyclinder : %02xh", partitionEntry.iStartCylinder)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" System ID : %02xh", partitionEntry.iPartitionType)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Head : %02xh", partitionEntry.iEndHead)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Sector : %02xh", partitionEntry.iEndSector)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Cyclinder : %02xh", partitionEntry.iEndCylinder)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Relative Sector : %08xh", partitionEntry.iFirstSector)); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Number of Sectors: %08xh", partitionEntry.iNumSectors)); sl@0: 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); sl@0: 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); sl@0: // sl@0: // Clear all other partition entries and align the partition info into the minor buffer for writing... sl@0: // sl@0: memclr(iMinorBuf, KDiskSectorSize); sl@0: memcpy(&iMinorBuf[KMBRFirstPartitionEntry], &partitionEntry, sizeof(TMBRPartitionEntry)); sl@0: sl@0: *(TUint16*)(&iMinorBuf[KMBRSignatureOffset]) = 0xAA55; sl@0: sl@0: iSession->SetupCIMWriteBlock(0, iMinorBuf); sl@0: sl@0: // sl@0: // Write the partition table and engage the read to validate and complete the mount process sl@0: // sl@0: iMbrMissing = EFalse; sl@0: iCreateMbr = EFalse; sl@0: err = EngageAndSetWriteRequest(EMReqUpdatePtnInfo); sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("iEntry[0], defPartition.iFirstSector, defPartition.iNumSectors); sl@0: iHiddenSectors = defPartition.iFirstSector; sl@0: iPartitionInfo->iPartitionCount = 1; sl@0: iPartitionInfo->iMediaSizeInBytes = TotalSizeInBytes(); sl@0: } sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CREATEDEFAULTPARTITION_EXIT, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: TInt DMmcMediaDriverFlash::GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry) sl@0: /** sl@0: Calculates the default patition information for an specific card. sl@0: @param aPartitionEntry The TMBRPartitionEntry to be filled in with the format parameters sl@0: @return Standard Symbian OS Error Code sl@0: */ sl@0: { sl@0: memclr(&aPartitionEntry, sizeof(TMBRPartitionEntry)); sl@0: TUint16 reservedSectors; // Not used sl@0: TInt r = GetMediaDefaultPartitionInfo(aPartitionEntry, reservedSectors, iCard); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: void DMmcMediaDriverFlash::SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors) sl@0: // sl@0: // auxiliary static function to record partition information in TPartitionEntry object sl@0: // sl@0: { sl@0: OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_SETPARTITIONENTRY_ENTRY ); sl@0: aEntry->iPartitionBaseAddr=aFirstSector; sl@0: aEntry->iPartitionBaseAddr<<=KDiskSectorShift; sl@0: aEntry->iPartitionLen=aNumSectors; sl@0: aEntry->iPartitionLen<<=KDiskSectorShift; sl@0: aEntry->iPartitionType=KPartitionTypeFAT12; sl@0: OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_SETPARTITIONENTRY_EXIT ); sl@0: } sl@0: sl@0: TInt DMmcMediaDriverFlash::DoPasswordOp() sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPASSWORDOP_ENTRY, this ); sl@0: // Reconstruct password data structure in our address space sl@0: TLocalDrivePasswordData clientData; sl@0: TInt r = iCurrentReq->ReadRemoteRaw(&clientData, sizeof(TLocalDrivePasswordData)); sl@0: sl@0: TMediaPassword oldPassword; sl@0: if (r == KErrNone) sl@0: r = iCurrentReq->ReadRemote(clientData.iOldPasswd, &oldPassword); sl@0: sl@0: TMediaPassword newPassword; sl@0: if (r == KErrNone) sl@0: r = iCurrentReq->ReadRemote(clientData.iNewPasswd, &newPassword); sl@0: sl@0: TLocalDrivePasswordData passData(oldPassword, newPassword, clientData.iStorePasswd); sl@0: sl@0: if (r == KErrNone) sl@0: { sl@0: TInt id=iCurrentReq->Id(); sl@0: switch (id) sl@0: { sl@0: case DLocalDrive::EPasswordUnlock: sl@0: r = LaunchRPIUnlock(passData); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:pc:%d", (TInt) aFunc)); sl@0: __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EPCInUse)); sl@0: __ASSERT_DEBUG(aFunc == DLocalDrive::EPasswordLock || aFunc == DLocalDrive::EPasswordClear, Panic(EPCFunc)); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: TInt r; sl@0: sl@0: if ((r = CheckDevice(EMReqTypeChangePswd)) == KErrNone) sl@0: { sl@0: // check if the current password is correct here. (This makes the sl@0: // clear operation redundant only if the password is stored and it sl@0: // is wrong.) Complete with same value as DoSessionEndDfc() would. sl@0: sl@0: TMediaPassword curPwd; sl@0: sl@0: curPwd = *aData.iOldPasswd; sl@0: TInt curPwdLen = curPwd.Length(); sl@0: TInt blockLen; sl@0: sl@0: if (!(iCard->iFlags & KMMCardIsLockable)) sl@0: r = KErrNotSupported; sl@0: else if (Stack().PasswordStore()->IsMappingIncorrect(iCard->CID(), curPwd)) sl@0: r = KErrAccessDenied; sl@0: else sl@0: { sl@0: if ((r = Stack().MMCSocket()->PrepareStore(CardNum(), aFunc, aData/*, aThread*/)) == KErrNone) sl@0: { sl@0: switch (aFunc) sl@0: { sl@0: case DLocalDrive::EPasswordLock: sl@0: { sl@0: TMediaPassword newPwd; sl@0: newPwd = *aData.iNewPasswd; sl@0: TInt newPwdLen = newPwd.Length(); sl@0: blockLen = 1 + 1 + curPwdLen + newPwdLen; sl@0: sl@0: #ifndef __EPOC32__ sl@0: TUint16 env_Var[]=L"_EPOC_PWD_LEN"; sl@0: TUint16 env_Val[2]; sl@0: env_Val[0]=(TUint16)(curPwdLen+1); sl@0: env_Val[1]=0;//make a null terminated string sl@0: r=SetEnvironmentVariable(env_Var,&env_Val[0]); sl@0: __ASSERT_DEBUG(r!=0, Panic(EPCFunc)); sl@0: sl@0: #endif sl@0: sl@0: TPtr8 pbuf(&iMinorBuf[0], 2, blockLen); sl@0: pbuf[0] = KMMCLockUnlockSetPwd; // LOCK_UNLOCK = 0, SET_PWD = 1 sl@0: pbuf[1] = static_cast(curPwdLen + newPwdLen); sl@0: pbuf.Append(curPwd); sl@0: pbuf.Append(newPwd); sl@0: } sl@0: break; sl@0: sl@0: case DLocalDrive::EPasswordClear: sl@0: { sl@0: blockLen = 1 + 1 + curPwdLen; sl@0: sl@0: TPtr8 pbuf(&iMinorBuf[0], 2, blockLen); sl@0: pbuf[0] = KMMCLockUnlockClrPwd; // LOCK_UNLOCK = dc, CLR_PWD = 1 sl@0: pbuf[1] = static_cast(curPwdLen); sl@0: pbuf.Append(curPwd); sl@0: } sl@0: break; sl@0: sl@0: default: sl@0: // DLocalDrive::EPasswordUnlock is not handled. This avoids warnings for unused sl@0: // case, and uninitialized variable. sl@0: blockLen = 0; sl@0: break; sl@0: } // switch (aFunc) sl@0: sl@0: iSession->SetupCIMLockUnlock(blockLen, iMinorBuf); sl@0: r = EngageAndSetWriteRequest(EMReqPswdCtrl); sl@0: } // if ((r = Stack().PrepareStore(CardNum(), aFunc, aData, aThread)) == KErrNone) sl@0: } // else (Stack().IsMappingIncorrect(iCard->CID(), curPwd)) sl@0: } // (r = CheckDevice(EMReqTypeChangePswd)) == KErrNone sl@0: sl@0: // complete immediately if error occured sl@0: if (r != KErrNone) sl@0: CompleteRequest(r); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:cd:%d",aReqType)); sl@0: sl@0: TInt r=KErrNone; sl@0: sl@0: if (!iCard->IsReady()) sl@0: r=KErrNotReady; sl@0: sl@0: // The card must be locked if attempting to unlock during RPI, and sl@0: // unlocked at all other times. sl@0: else if (aReqType!=EMReqTypeUnlockPswd && iCard->IsLocked()) sl@0: r=KErrLocked; sl@0: // Don't perform Password setting for WriteProtected cards, sl@0: // unable to recover (ForcedErase) if password lost. sl@0: else if (aReqType==EMReqTypeChangePswd) sl@0: { sl@0: if (iCard->MediaType()==EMultiMediaROM) sl@0: { sl@0: r=KErrAccessDenied; sl@0: } sl@0: } sl@0: else if (iMbrMissing && aReqType==EMReqTypeNormalRd) sl@0: r=KErrCorrupt; sl@0: sl@0: #if !defined(__WINS__) sl@0: // Don't perform write/password operations when the battery is low sl@0: // else if (aReqType!=EMReqTypeNormalRd && Hal::MainBatteryStatus()IsWriteProtected()) sl@0: r=KErrAccessDenied; sl@0: // Don't perform write/format operations on MMC ROM cards sl@0: else if (iMediaType==EMultiMediaROM && aReqType == EMReqTypeNormalWr) sl@0: r=KErrAccessDenied; sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("(aMediaDriver); sl@0: __ASSERT_DEBUG(! md.iSessionEndDfc.Queued(), Panic(ESECBQueued)); sl@0: md.iSessionEndDfc.Enque(); sl@0: OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_SESSIONENDCALLBACK_EXIT ); sl@0: } sl@0: sl@0: sl@0: void DMmcMediaDriverFlash::SessionEndDfc(TAny* aMediaDriver) sl@0: { sl@0: static_cast(aMediaDriver)->DoSessionEndDfc(); sl@0: } sl@0: sl@0: sl@0: void DMmcMediaDriverFlash::DoSessionEndDfc() sl@0: // sl@0: // launch next session or complete client request sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dsed:%d", CurrentRequest())); sl@0: OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_REQUEST, "Current Request=%d", CurrentRequest()); sl@0: sl@0: TInt r=KErrNone; sl@0: sl@0: EndInCritical(); sl@0: sl@0: // Abort if writing or formatting and power has gone down sl@0: if (!Kern::PowerGood() && CurrentRequest()!=EMReqRead) sl@0: r=KErrAbort; sl@0: // Return KErrNotReady if we have has a deferred media change sl@0: if (!iCard->IsReady()) sl@0: r=KErrNotReady; sl@0: // if stack has powered down session pointer will be NULL sl@0: if (iSession == NULL) sl@0: r = KErrNotReady; sl@0: sl@0: TBool complete = ETrue; sl@0: sl@0: if (r==KErrNone) sl@0: { sl@0: r = iSession->EpocErrorCode(); sl@0: sl@0: switch (CurrentRequest()) sl@0: { sl@0: case EMReqRead: sl@0: { sl@0: if (r != KErrNone) // abort if MMC error sl@0: break; sl@0: sl@0: if(iDoDoubleBuffer) sl@0: { sl@0: // sl@0: // This is the end of a double-buffered transfer. sl@0: // - Now we have two buffers to copy back to the user... sl@0: // sl@0: TUint8* bufPtr = iIntBuf + (iSecondBuffer ? (iMaxBufSize >> 1) : 0); sl@0: if((r = WriteDataToUser(bufPtr)) == KErrNone) sl@0: { sl@0: MarkBlocks(iReqCur, iPhysEnd, CchMemToIdx(bufPtr)); sl@0: sl@0: iReqCur = iPhysEnd; sl@0: iPhysEnd = iDbEnd; sl@0: sl@0: bufPtr = iIntBuf + (iSecondBuffer ? 0 : (iMaxBufSize >> 1)); sl@0: if((r = WriteDataToUser(bufPtr)) == KErrNone) sl@0: { sl@0: MarkBlocks(iReqCur, (iPhysEnd + iBlkMsk) & ~iBlkMsk, CchMemToIdx(bufPtr)); sl@0: } sl@0: } sl@0: iDoDoubleBuffer = EFalse; sl@0: } sl@0: else if (iDoPhysicalAddress) sl@0: { sl@0: if (iRdROB & KIPCWrite) sl@0: { sl@0: // partial end point sl@0: TInt len = I64LOW(iReqEnd & iBlkMsk); sl@0: const TInt ofset = I64LOW(iPhysEnd - iBlkLen - iReqStart); sl@0: sl@0: TPtrC8 extrView(iIntBuf, len); sl@0: r = iCurrentReq->WriteRemote(&extrView,ofset); sl@0: } sl@0: // Reset attributes sl@0: iRdROB = 0; sl@0: iFragOfset = iIPCLen = iBufOfset = 0; sl@0: iReqCur = iPhysEnd = iReqEnd; sl@0: iDoPhysicalAddress = EFalse; sl@0: } sl@0: else sl@0: { sl@0: r = WriteDataToUser(&iIntBuf[I64LOW(iReqCur - iPhysStart)]); sl@0: } sl@0: sl@0: if (r != KErrNone) sl@0: break; sl@0: sl@0: // if there is more information to read for the user then engage another session sl@0: if ((iReqCur = iPhysEnd) < iReqEnd) sl@0: { sl@0: TBool allDone = EFalse; sl@0: if ( ((r = ReadDataUntilCacheExhausted(&allDone)) == KErrNone) && !allDone) sl@0: { sl@0: iPhysStart = iReqCur & ~iBlkMsk; sl@0: TUint32 length = I64LOW(iReqEnd - iReqCur); sl@0: sl@0: if ( (iReqEnd - iPhysStart) > iMaxBufSize && iSocket->SupportsDoubleBuffering() && !iReadToEndOfCard) sl@0: r = LaunchDBRead(); sl@0: else sl@0: r = LaunchRead(iReqCur, length); sl@0: sl@0: if ( r == KErrNone) sl@0: complete = EFalse; sl@0: } sl@0: } sl@0: } sl@0: break; sl@0: sl@0: case EMReqWrite: sl@0: { sl@0: if (r != KErrNone) // abort if MMC error sl@0: { sl@0: break; sl@0: } sl@0: sl@0: if (iWtRBM == 0) sl@0: { sl@0: iReqCur = iPhysEnd; sl@0: iDoDoubleBuffer = EFalse; sl@0: iDoPhysicalAddress = EFalse; sl@0: iRdROB = 0; sl@0: iFragOfset = iIPCLen = iBufOfset = 0; sl@0: } sl@0: // clear current RBM flag sl@0: else sl@0: { sl@0: if (iWtRBM & KWtRBMFst) sl@0: { sl@0: iWtRBM &= ~KWtRBMFst; sl@0: } sl@0: else if (iWtRBM & KWtRBMLst) sl@0: { sl@0: iWtRBM &= ~KWtRBMLst; sl@0: } sl@0: } sl@0: sl@0: // advance media position if just finished write, as opposed to read-before-modify sl@0: if (iReqCur < iReqEnd) sl@0: { sl@0: if ((r = LaunchWrite(iReqCur, I64LOW(iReqEnd - iReqCur), EMReqWrite)) == KErrNone) sl@0: { sl@0: complete = EFalse; sl@0: } sl@0: sl@0: complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse; sl@0: } sl@0: } sl@0: break; sl@0: sl@0: case EMReqFormat: sl@0: { sl@0: if (r != KErrNone) // abort if MMC error sl@0: break; sl@0: sl@0: if ((iEraseUnitMsk == KMaxTUint64) || // no erase unit defined (Erase Class Commands not supported) ? sl@0: (iPhysEnd == iReqEnd) || // finshed already ? sl@0: ((iPhysStart & iEraseUnitMsk) == 0 && (iPhysEnd & iEraseUnitMsk) == 0)) sl@0: { sl@0: iReqCur = iPhysEnd; sl@0: } sl@0: else sl@0: { sl@0: // Formating to a mis-aligned boundary, so we can't make best use of sl@0: // multiple erase blocks. We shall simply erase up to the next block sl@0: // boundary, and return the adjustment info to the file system sl@0: r = I64LOW(iPhysEnd - iPhysStart); sl@0: iReqCur = iReqEnd; sl@0: } sl@0: sl@0: if(r == KErrNone) sl@0: { sl@0: // advance media position if just finished write, as opposed to read-before-modify sl@0: if (iReqCur < iReqEnd) sl@0: { sl@0: if ((r = LaunchFormat(iReqCur, I64LOW(iReqEnd - iReqCur))) == KErrNone) sl@0: { sl@0: complete = EFalse; sl@0: } sl@0: } sl@0: // if format finished, write an MBR if required sl@0: // Always write an MBR if it's an SD card sl@0: else if (iCreateMbr) sl@0: { sl@0: // Finished Format, so write the MBR/default partition table if required sl@0: r = WritePartitionInfo(); sl@0: complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse; sl@0: } sl@0: } sl@0: } sl@0: break; sl@0: sl@0: case EMReqPtnInfo: sl@0: if (r == KErrNone) sl@0: r = DecodePartitionInfo(); // set up iPartitionInfo sl@0: sl@0: PartitionInfoComplete(r == KErrNone?KErrNone:KErrNotReady); sl@0: break; sl@0: sl@0: case EMReqEMMCPtnInfo: sl@0: iMedReq = EMReqIdle; sl@0: // For now do nothing.. sl@0: break; sl@0: sl@0: case EMReqUpdatePtnInfo: sl@0: break; sl@0: sl@0: case EMReqPswdCtrl: sl@0: if (r == KErrLocked) sl@0: r = KErrAccessDenied; sl@0: break; sl@0: sl@0: case EMReqForceErase: sl@0: sl@0: if (r == KErrNone) sl@0: { sl@0: // Finished Forced Erase , so write the default partition table... sl@0: r = WritePartitionInfo(); sl@0: } sl@0: sl@0: complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse; sl@0: break; sl@0: sl@0: case EMReqWritePasswordData: sl@0: // sl@0: // WritePasswordData also kicks off an auto-unlock session to ensure that sl@0: // any locked cards that have passwords in the password store are immediately sl@0: // available. We can safely ignore any errors returned at this stage, as the sl@0: // password store will have been successfully updated (in locmedia.cpp), even sl@0: // if the card is unable to accept the password. sl@0: // sl@0: r = KErrNone; sl@0: break; sl@0: sl@0: case EMReqIdle: sl@0: // request has been completed already (e.g. due to a power down) sl@0: break; sl@0: sl@0: sl@0: default: sl@0: __ASSERT_DEBUG(EFalse, Panic(EDSEDRequest)); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: // r != KErrNone => complete sl@0: __ASSERT_DEBUG(!(r != KErrNone) || complete, Panic(EDSEDNotErrComplete)); sl@0: sl@0: if (complete) sl@0: { sl@0: if (r != KErrNone) sl@0: InvalidateCache(); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("(aMediaDriver); sl@0: __ASSERT_DEBUG(! md.iDataTransferCallBackDfc.Queued(), Panic(EDBCBQueued)); sl@0: md.iDataTransferCallBackDfc.Enque(); sl@0: OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACK_EXIT ); sl@0: } sl@0: sl@0: void DMmcMediaDriverFlash::DataTransferCallBackDfc(TAny* aMediaDriver) sl@0: { sl@0: OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACKDFC_ENTRY ); sl@0: DMmcMediaDriverFlash& md = *static_cast(aMediaDriver); sl@0: sl@0: if (md.iDoPhysicalAddress) sl@0: { sl@0: if(md.CurrentRequest() == EMReqWrite) sl@0: { sl@0: md.DoPhysWriteDataTransferCallBack(); sl@0: } sl@0: else sl@0: { sl@0: md.DoPhysReadDataTransferCallBack(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if(md.CurrentRequest() == EMReqWrite) sl@0: { sl@0: md.DoWriteDataTransferCallBack(); sl@0: } sl@0: else sl@0: { sl@0: md.DoReadDataTransferCallBack(); sl@0: } sl@0: } sl@0: OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACKDFC_EXIT ); sl@0: } sl@0: sl@0: void DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack() sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()")); sl@0: sl@0: TInt err = KErrNone; sl@0: sl@0: if ( (iRdROB & KIPCSetup) || ((iReqEnd - iPhysEnd) < iBlkLen) ) sl@0: { sl@0: //IPC to be setup, or partial end block read sl@0: iRdROB &= ~KIPCSetup; sl@0: sl@0: if ((iReqEnd - iPhysEnd) < iBlkLen) sl@0: { sl@0: iIntBuf = iCacheBuf; sl@0: } sl@0: else sl@0: { sl@0: TPtr8 tgt(iMinorBuf, iBlkLen); sl@0: err = ReadDataFromUser(tgt, I64LOW(iPhysEnd-iReqStart)); sl@0: iIntBuf = iMinorBuf; sl@0: } sl@0: sl@0: iReqCur = iPhysEnd; sl@0: iPhysEnd += iBlkLen; sl@0: iBufOfset = 0; sl@0: iIPCLen = iBlkLen; sl@0: sl@0: #if !defined(__WINS__) sl@0: iSession->MoreDataAvailable( (TInt)(iBlkLen >> KDiskSectorShift), (TUint8*)Epoc::LinearToPhysical((TLinAddr) iIntBuf), err); sl@0: #else sl@0: iSession->MoreDataAvailable( (TInt)(iBlkLen >> KDiskSectorShift), iIntBuf, err); sl@0: #endif sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("--iDoPhysicalAddress(KIPCSetup)")); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_EXIT1, this ); sl@0: return; sl@0: } sl@0: sl@0: PrepareNextPhysicalFragment(); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()")); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_EXIT2, this ); sl@0: } sl@0: sl@0: sl@0: void DMmcMediaDriverFlash::DoPhysReadDataTransferCallBack() sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoPhysReadTransferCallBack()")); sl@0: sl@0: TInt err = KErrNone; sl@0: sl@0: if ((iRdROB & KIPCWrite) && !iSecondBuffer) sl@0: { sl@0: // an IPC transfer completed sl@0: iRdROB &= ~KIPCWrite; sl@0: if(iNxtIPCLen) sl@0: { sl@0: // First transfer is an IPC, sl@0: // Corner-case - transfer is most likely IPC-DMA-IPC, sl@0: // because write cannot occur until after the first 2 iterations it is possible to arrive here with both IPCSetup & IPCWrite Set. sl@0: // need to use iIPCNxtLen instead sl@0: TPtrC8 extrView(&iIntBuf[iBufOfset], iNxtIPCLen); sl@0: err = iCurrentReq->WriteRemote(&extrView,I64LOW(iReqCur - iReqStart)); sl@0: iNxtIPCLen = iBufOfset = 0; sl@0: } sl@0: else sl@0: { sl@0: TPtrC8 extrView(&iIntBuf[iBufOfset], iIPCLen); sl@0: err = iCurrentReq->WriteRemote(&extrView,I64LOW(iReqCur - iReqStart)); sl@0: iIPCLen = iBufOfset = 0; sl@0: } sl@0: } sl@0: sl@0: if ( (iRdROB & KIPCSetup) || ((iReqEnd - iPhysEnd) < iBlkLen) ) sl@0: { sl@0: // IPC to be setup, or partial end block read. sl@0: iRdROB &= ~KIPCSetup; sl@0: iRdROB |= KIPCWrite; sl@0: sl@0: iIntBuf = ReserveReadBlocks(iPhysEnd,(iPhysEnd+iBlkLen), &iIPCLen); sl@0: sl@0: iReqCur = iPhysEnd; sl@0: iPhysEnd += iIPCLen; sl@0: iBufOfset = 0; sl@0: #if !defined(__WINS__) sl@0: iSession->MoreDataAvailable( (TInt)(iIPCLen >> KDiskSectorShift), (TUint8*)Epoc::LinearToPhysical((TLinAddr) iIntBuf), err); sl@0: #else sl@0: iSession->MoreDataAvailable( (TInt)(iIPCLen >> KDiskSectorShift), iIntBuf, err); sl@0: #endif sl@0: iSecondBuffer = ETrue; sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("--iDoPhysicalAddress(KIPCWrite)")); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_EXIT1, this ); sl@0: return; sl@0: } sl@0: sl@0: PrepareNextPhysicalFragment(); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoPhysReadTransferCallBack()")); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_EXIT2, this ); sl@0: } sl@0: sl@0: void DMmcMediaDriverFlash::DoWriteDataTransferCallBack() sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOWRITEDATATRANSFERCALLBACK_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoWriteDataTransferCallBack()")); sl@0: sl@0: TInt err = KErrNone; sl@0: sl@0: // Advance current request progress... sl@0: iReqCur = iPhysEnd; sl@0: sl@0: const TUint32 doubleBufferSize = iMaxBufSize >> 1; sl@0: sl@0: TInt64 length = iDbEnd - iReqCur; sl@0: TInt64 medEnd = UMin(iReqCur + doubleBufferSize, iReqCur + length); sl@0: sl@0: iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk; sl@0: TInt64 len = UMin(iDbEnd, iPhysEnd) - iReqCur; sl@0: sl@0: if(len > doubleBufferSize) sl@0: { sl@0: // Adjust for maximum size of double-buffering sl@0: len = doubleBufferSize; sl@0: } sl@0: sl@0: __ASSERT_DEBUG(len > 0, Panic(EDBLength)); sl@0: __ASSERT_DEBUG(I64HIGH((len + (KDiskSectorSize-1)) >> KDiskSectorShift) == 0, Panic(EDBLengthTooBig)); sl@0: sl@0: TUint32 numBlocks = I64LOW((len + (KDiskSectorSize-1)) >> KDiskSectorShift); sl@0: sl@0: const TInt64 usrOfst = (iReqCur - iReqStart); sl@0: sl@0: __ASSERT_DEBUG(I64HIGH(usrOfst) == 0, Panic(EDBOffsetTooBig)); sl@0: sl@0: // Setup the next buffer pointer and switch buffers... sl@0: TUint8* bufPtr = iIntBuf + (iSecondBuffer ? doubleBufferSize : 0); sl@0: TPtr8 tgt(bufPtr, I64LOW(len)); sl@0: iSecondBuffer = iSecondBuffer ? (TBool)EFalse : (TBool)ETrue; sl@0: sl@0: if(iDoLastRMW && length < doubleBufferSize) sl@0: { sl@0: // sl@0: // This is the last transfer, and RMW is required. The result of the read exists sl@0: // in iMinorBuf, so copy the non-modified section of the block to the active buffer. sl@0: // sl@0: memcpy(&bufPtr[(numBlocks-1) << KDiskSectorShift], iMinorBuf, KDiskSectorSize); sl@0: } sl@0: sl@0: if(I64LOW(iDbEnd - iReqCur) <= iMaxBufSize) sl@0: { sl@0: // sl@0: // This is the last transfer (with or without RMW) sl@0: // - Mark the last blocks as active in the buffer cache. sl@0: // sl@0: MarkBlocks(iReqCur, iPhysEnd, CchMemToIdx(bufPtr)); sl@0: } sl@0: sl@0: // sl@0: // Read the requested data from the remote thread... sl@0: // sl@0: err = ReadDataFromUser(tgt, I64LOW(usrOfst)); sl@0: sl@0: // sl@0: // ...and signal that data is available to the PSL. sl@0: // sl@0: iSession->MoreDataAvailable(numBlocks, bufPtr, err); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoWriteDataTransferCallBack()")); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOWRITEDATATRANSFERCALLBACK_EXIT, this ); sl@0: } sl@0: sl@0: sl@0: void DMmcMediaDriverFlash::DoReadDataTransferCallBack() sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoReadTransferCallBack()")); sl@0: sl@0: TInt err = KErrNone; sl@0: sl@0: const TUint32 doubleBufferSize = iMaxBufSize >> 1; sl@0: sl@0: TUint32 bufOfst = 0; sl@0: sl@0: if((iReqCur & ~iBlkMsk) == iPhysStart) sl@0: { sl@0: if(iSecondBuffer) sl@0: { sl@0: // sl@0: // If this is the first callback, don't copy data as it's not available yet sl@0: // - just drop through to set up the next buffer. sl@0: // sl@0: TUint32 numBlocks = I64LOW((doubleBufferSize + (KDiskSectorSize-1)) >> KDiskSectorShift); sl@0: TUint8* bufPtr = iIntBuf + doubleBufferSize; sl@0: sl@0: iSecondBuffer = EFalse; sl@0: sl@0: iSession->MoreDataAvailable(numBlocks, bufPtr, KErrNone); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_EXIT1, this ); sl@0: return; sl@0: } sl@0: else sl@0: { sl@0: // sl@0: // If this is the second callback we're ready to copy sl@0: // back to the client - data may be mis-aligned in the first sl@0: // instance, but all subsequent data will be aligned... sl@0: // sl@0: bufOfst = I64LOW(iReqCur - iPhysStart); sl@0: } sl@0: } sl@0: sl@0: // ...otherwise, write the previous buffer contents to the user sl@0: TUint8* bufPtr = iIntBuf + (iSecondBuffer ? doubleBufferSize : 0); sl@0: sl@0: err = WriteDataToUser(bufPtr + bufOfst); sl@0: sl@0: // Advance current request progress... sl@0: iReqCur = iPhysEnd; sl@0: sl@0: TInt64 medEnd = UMin(iReqCur + doubleBufferSize, iDbEnd); sl@0: sl@0: iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk; sl@0: sl@0: // Current buffer is one step ahead of the current request progress... sl@0: TInt64 len = UMin((iDbEnd - iPhysEnd + iBlkMsk) & ~iBlkMsk, TInt64(doubleBufferSize)); sl@0: sl@0: __ASSERT_DEBUG(len == 0 || (I64HIGH((len + (KDiskSectorSize-1)) >> KDiskSectorShift) == 0), Panic(EDBLengthTooBig)); sl@0: sl@0: TUint32 numBlocks = I64LOW((len + (KDiskSectorSize-1)) >> KDiskSectorShift); sl@0: sl@0: // sl@0: // ...switch buffers and signal that data is available to the PSL. sl@0: // sl@0: iSecondBuffer = iSecondBuffer ? (TBool)EFalse : (TBool)ETrue; sl@0: sl@0: iSession->MoreDataAvailable(numBlocks, bufPtr, err); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoDataTransferCallBack()")); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_EXIT2, this ); sl@0: } sl@0: sl@0: sl@0: // ---- request management ---- sl@0: sl@0: sl@0: TInt DMmcMediaDriverFlash::EngageAndSetReadRequest(DMmcMediaDriverFlash::TMediaRequest aRequest) sl@0: { sl@0: OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETREADREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetReadRequest;aRequest=%d;this=%x", (TInt) aRequest, (TUint) this); sl@0: TInt r = EngageAndSetRequest(aRequest, iReadCurrentInMilliAmps); sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETREADREQUEST_EXIT, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: TInt DMmcMediaDriverFlash::EngageAndSetWriteRequest(DMmcMediaDriverFlash::TMediaRequest aRequest) sl@0: { sl@0: OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETWRITEREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetReadRequest;aRequest=%d;this=%x", (TInt) aRequest, (TUint) this); sl@0: TInt r = EngageAndSetRequest(aRequest, iWriteCurrentInMilliAmps); sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETWRITEREQUEST_EXIT, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: TInt DMmcMediaDriverFlash::EngageAndSetRequest(DMmcMediaDriverFlash::TMediaRequest aRequest, TInt aCurrent) sl@0: // sl@0: // In WINS, all of the processing, including the callbacks, is done when Engage() is called, sl@0: // so the request value must be set up in advanced. Both the request and the current are sl@0: // cleared in the corresponding call to CompleteRequest(). sl@0: // sl@0: { sl@0: OstTraceExt3(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetRequest;aRequest=%d;aCurrent=%d;this=%x", (TInt) aRequest, aCurrent, (TUint) this); sl@0: __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); sl@0: sl@0: iMedReq = aRequest; sl@0: SetCurrentConsumption(aCurrent); sl@0: sl@0: TInt r = InCritical(); sl@0: if (r == KErrNone) sl@0: { sl@0: r = iSession->Engage(); sl@0: } sl@0: sl@0: if(r != KErrNone) sl@0: { sl@0: if (!Kern::PowerGood()) sl@0: r=KErrAbort; // If emergency power down - return abort rather than anything else. sl@0: if (!iCard->IsReady()) sl@0: r=KErrNotReady; // If media change - return not ready rather than anything else. sl@0: EndInCritical(); sl@0: } sl@0: sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETREQUEST_EXIT, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: void DMmcMediaDriverFlash::CompleteRequest(TInt aReason) sl@0: // sl@0: // completes the specified request sl@0: // sl@0: { sl@0: OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_COMPLETEREQUEST_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:cr0x%08x,%d", iCurrentReq, aReason)); sl@0: sl@0: iMedReq = EMReqIdle; sl@0: SetCurrentConsumption(KIdleCurrentInMilliAmps); sl@0: sl@0: TLocDrvRequest* pR=iCurrentReq; sl@0: if (pR) sl@0: { sl@0: #ifdef __DEMAND_PAGING__ sl@0: #if defined(__TEST_PAGING_MEDIA_DRIVER__) sl@0: __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Complete req Id(%d) with(%d)", pR->Id(), aReason)); sl@0: #endif // __TEST_PAGING_MEDIA_DRIVER__ sl@0: #endif // __DEMAND_PAGING__ sl@0: iCurrentReq=NULL; sl@0: DMediaDriver::Complete(*pR,aReason); sl@0: } sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_COMPLETEREQUEST_EXIT, this ); sl@0: } sl@0: sl@0: TInt DMmcMediaDriverFlash::Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo) sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CAPS_ENTRY, this ); sl@0: // Fill buffer with current media caps. sl@0: aInfo.iType = EMediaHardDisk; sl@0: aInfo.iConnectionBusType = EConnectionBusInternal; sl@0: aInfo.iDriveAtt = KDriveAttLocal; sl@0: aInfo.iMediaAtt = KMediaAttFormattable; sl@0: sl@0: if(iCard->iFlags & KMMCardIsLockable) sl@0: aInfo.iMediaAtt |= KMediaAttLockable; sl@0: sl@0: if (iCard->HasPassword()) sl@0: aInfo.iMediaAtt |= KMediaAttHasPassword; sl@0: if (iCard->IsWriteProtected()) sl@0: aInfo.iMediaAtt |= KMediaAttWriteProtected; sl@0: if (iCard->IsLocked()) sl@0: aInfo.iMediaAtt |= KMediaAttLocked; sl@0: sl@0: aInfo.iFileSystemId = KDriveFileSysFAT; sl@0: sl@0: // Format is performed in multiples of the erase sector (or multiple block) size sl@0: aInfo.iMaxBytesPerFormat = iEraseInfo.iPreferredEraseUnitSize; sl@0: sl@0: if ((!iInternalSlot) && (GetCardFormatInfo(iCard,aInfo.iFormatInfo) == KErrNone)) sl@0: { sl@0: TUint16 reservedSectors; sl@0: TMBRPartitionEntry dummy; // Not used here sl@0: const TInt r = GetMediaDefaultPartitionInfo(dummy, reservedSectors, iCard); sl@0: if(r != KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CAPS_EXIT1, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: aInfo.iFormatInfo.iReservedSectors = reservedSectors; sl@0: aInfo.iExtraInfo = ETrue; sl@0: } sl@0: sl@0: // Set serial number to CID sl@0: __ASSERT_DEBUG(KMMCCIDLength<=KMaxSerialNumLength, Kern::PanicCurrentThread(_L("Mmc"), KErrOverflow)); sl@0: aInfo.iSerialNumLength = KMMCCIDLength; sl@0: for (TUint i=0; iCID().At(i); sl@0: sl@0: // Get block size & erase block size to allow the file system to align first usable cluster correctly sl@0: aInfo.iBlockSize = BlockSize(iCard); sl@0: aInfo.iEraseBlockSize = EraseBlockSize(iCard); sl@0: sl@0: #if defined(__DEMAND_PAGING__) sl@0: // If the stack has flagged this as a demand-paging device, then it is assumed that it is internal sl@0: // and (optionally) write protected. sl@0: if(aDrive.iPrimaryMedia->iPagingMedia) sl@0: { sl@0: aInfo.iMediaAtt|= KMediaAttPageable; sl@0: if (iDemandPagingInfo.iWriteProtected) sl@0: { sl@0: aInfo.iMediaAtt|= KMediaAttWriteProtected; sl@0: aInfo.iMediaAtt&= ~KMediaAttFormattable; sl@0: } sl@0: } sl@0: sl@0: // code paging enabled on this drive ? sl@0: if(aDrive.iPagingDrv) sl@0: { sl@0: aInfo.iDriveAtt|= KDriveAttPageable; sl@0: } sl@0: sl@0: #endif sl@0: sl@0: if (iInternalSlot) sl@0: { sl@0: aInfo.iDriveAtt|= KDriveAttInternal; sl@0: } sl@0: else sl@0: { sl@0: aInfo.iDriveAtt|= KDriveAttRemovable; sl@0: } sl@0: sl@0: sl@0: if (iMmcPartitionInfo) sl@0: { sl@0: TLocalDriveCapsV6Buf CapsInfo = aInfo; sl@0: iMmcPartitionInfo->PartitionCaps(aDrive,CapsInfo); sl@0: aInfo = CapsInfo(); sl@0: } sl@0: sl@0: sl@0: if (iMediaType==EMultiMediaROM) sl@0: { sl@0: aInfo.iMediaAtt|= KMediaAttWriteProtected; sl@0: aInfo.iMediaAtt&= ~KMediaAttFormattable; sl@0: } sl@0: sl@0: // Must return KErrCompletion to indicate that this sl@0: // is a synchronous version of the function sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CAPS_EXIT2, this, KErrCompletion ); sl@0: return KErrCompletion; sl@0: } sl@0: sl@0: sl@0: // ---- cache ---- sl@0: sl@0: TInt DMmcMediaDriverFlash::ReadDataUntilCacheExhausted(TBool* aAllDone) sl@0: // sl@0: // scans the cache for blocks corresponding to the range iReqCur to iReqEnd and sl@0: // writes them to user memory. Starts at iReqCur & ~iBlkMsk and looks for blocks sl@0: // at sequential media positions. Completes when a block is not available, even sl@0: // if a following block is available in the cache. *aAllDone is undefined if the sl@0: // return value is not KErrNone. sl@0: // sl@0: // This function is linear in the number of blocks in the cache. sl@0: // sl@0: { sl@0: OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rdc:%x,%x", iReqCur, iReqEnd)); sl@0: OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED, "iReqCur=0x%x; iReqEnd=0x%x", (TUint) iReqCur, (TUint) iReqEnd ); sl@0: sl@0: if ( iCurrentReq->IsPhysicalAddress() sl@0: #if defined(__DEMAND_PAGING__) && !defined(__WINS__) sl@0: || DMediaPagingDevice::PageInRequest(*iCurrentReq) sl@0: #endif //DEMAND_PAGING sl@0: ) sl@0: { sl@0: *aAllDone = EFalse; sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED_EXIT1, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt64 physStart = iReqCur & ~iBlkMsk; sl@0: TInt64 physEnd = Min(physStart + iMaxBufSize, (iReqEnd + iBlkMsk) & ~iBlkMsk); sl@0: BuildGammaArray(physStart, physEnd); sl@0: sl@0: TInt r = KErrNone; sl@0: TInt curBlk = 0; sl@0: TInt cchBlk; sl@0: while ( sl@0: r == KErrNone sl@0: && physStart + (curBlk << iBlkLenLog2) < physEnd sl@0: && (cchBlk = iGamma[curBlk]) != KNoCacheBlock ) sl@0: { sl@0: // set up instance variables for WriteDataToUser() sl@0: iPhysStart = physStart + (curBlk << iBlkLenLog2); sl@0: iPhysEnd = iPhysStart + iBlkLen; sl@0: iIntBuf = IdxToCchMem(cchBlk); sl@0: sl@0: if ((r = WriteDataToUser(&iIntBuf[I64LOW(iReqCur - iPhysStart)])) == KErrNone) sl@0: { sl@0: iReqCur = iPhysEnd; sl@0: iLstUsdCchEnt = iGamma[curBlk]; sl@0: ++curBlk; sl@0: } sl@0: } sl@0: sl@0: *aAllDone = (iReqCur >= iReqEnd); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("WriteToPageHandler((TUint8 *)(&extrView[0]), len, usrOfst); sl@0: else sl@0: #endif // __DEMAND_PAGING__ sl@0: r = iCurrentReq->WriteRemote(&extrView,usrOfst); sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_LATENCY2, "End writing user data" ); sl@0: sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_EXIT, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: TInt DMmcMediaDriverFlash::ReadDataFromUser(TDes8& aDes, TInt aOffset) sl@0: { sl@0: OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_READDATAFROMUSER_ENTRY ,"DMmcMediaDriverFlash::ReadDataFromUser;aOffset=%d;this=%x", aOffset, (TUint) this); sl@0: TInt r = KErrNotSupported; sl@0: #ifndef __WINS__ sl@0: if (DMediaPagingDevice::PageOutRequest(*iCurrentReq)) sl@0: { sl@0: r = iCurrentReq->ReadFromPageHandler((TAny*) aDes.Ptr(), aDes.MaxLength(), aOffset); sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT1, this, r ); sl@0: return r; sl@0: } sl@0: else sl@0: #endif // #ifndef __WINS__ sl@0: r = iCurrentReq->ReadRemote(&aDes, aOffset); sl@0: sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT2, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: TInt DMmcMediaDriverFlash::AdjustPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength) sl@0: // sl@0: // Retrieve next Physical memory fragment and adjust the start pointer and length with sl@0: // respect to the set offset {iFragOfset}. sl@0: // Note the offset may encompass multiple memory fragments. sl@0: // sl@0: { sl@0: OstTraceExt3(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_ENTRY, "DMmcMediaDriverFlash::AdjustPhysicalFragment;aPhysAddr=%x;aPhysLength=%d;this=%x", (TUint) aPhysAddr, aPhysLength, (TUint) this); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:APF")); sl@0: sl@0: TInt err = KErrNone; sl@0: TInt offset = iFragOfset; sl@0: sl@0: do sl@0: { sl@0: err = iCurrentReq->GetNextPhysicalAddress(aPhysAddr, aPhysLength); sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_EXIT1, this, err ); sl@0: return err; sl@0: } sl@0: sl@0: if (offset >= aPhysLength) // more offset than in this physical chunk sl@0: { sl@0: offset -= aPhysLength; sl@0: } sl@0: else sl@0: { sl@0: // offset < physLength sl@0: // offset lies within the memory chunk sl@0: // Adjust length and address for first transfer sl@0: aPhysLength -= offset; sl@0: aPhysAddr += offset; sl@0: offset = -1; sl@0: } sl@0: sl@0: } while (offset >= 0); sl@0: sl@0: iFragOfset = 0; // reset offset now complete sl@0: sl@0: if (aPhysAddr == 0) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_EXIT2, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: // DMAHelper ensures memory is dma aligned sl@0: if ( (aPhysAddr & (iSocket->DmaAlignment()-1) ) ) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lr:Memory Fragment Not Word Aligned!")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_DMA, "Memory fragment not word aligned"); sl@0: Panic(ENotDMAAligned); sl@0: } sl@0: #endif //_DEBUG sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:PFPF")); sl@0: TInt r = KErrNone; sl@0: sl@0: r = AdjustPhysicalFragment(aPhysAddr, aPhysLength); sl@0: sl@0: if (r == KErrNone) sl@0: { sl@0: TUint len = I64LOW(iReqEnd & iBlkMsk); sl@0: if ( ((TUint32)aPhysLength >= aLength) && len ) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF-end block")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_EB, "End block"); sl@0: //next iteration will be an IPC for the end block sl@0: //There is enough space in physical memory to fit sl@0: //the extended read, but exceeds boundary for this request. sl@0: iIPCLen = len; sl@0: iRdROB |= KIPCSetup; // IPC setup for next iteration sl@0: aPhysLength -= len; sl@0: } sl@0: sl@0: if (aPhysLength & iBlkMsk) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF-straddles boundary")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_SB, "Straddles boundary"); sl@0: // block must be straddling a fragment boundary sl@0: // Next iteration must be an IPC sl@0: iRdROB |= KIPCSetup; sl@0: sl@0: // Calculate the offset into the next memory block sl@0: iFragOfset = I64LOW(iBlkLen - (aPhysLength & iBlkMsk)); sl@0: aPhysLength &= ~iBlkMsk; sl@0: } sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:PNPF")); sl@0: TInt err = KErrNone; sl@0: TPhysAddr physAddr = 0; sl@0: TInt physLength = 0; sl@0: sl@0: err = AdjustPhysicalFragment(physAddr, physLength); sl@0: sl@0: if (err == KErrNone) sl@0: { sl@0: if (iPhysEnd+physLength >= iReqEnd) sl@0: { sl@0: //Last physical transfer ... sl@0: TUint len = I64LOW(iReqEnd & iBlkMsk); sl@0: if (len) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF-end block")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_EB, "End block" ); sl@0: sl@0: // end point not block aligned! sl@0: // next iteration must be an IPC call sl@0: iRdROB |= KIPCSetup; sl@0: iIPCLen = len; sl@0: physLength -= len; sl@0: } sl@0: else{ sl@0: physLength = I64LOW(iDbEnd - iPhysEnd); sl@0: } sl@0: } sl@0: sl@0: if (physLength & iBlkMsk) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF-straddles boundary")); sl@0: OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_SB, "Straddles boundary" ); sl@0: sl@0: // block must be straddling a fragment boundary sl@0: // Next iteration must be an IPC sl@0: iRdROB |= KIPCSetup; sl@0: sl@0: // Calculate the offset into the next memory block sl@0: iFragOfset = I64LOW(iBlkLen - (physLength & iBlkMsk)); sl@0: physLength &= ~iBlkMsk; sl@0: } sl@0: sl@0: iPhysEnd += physLength; sl@0: } sl@0: sl@0: iSession->MoreDataAvailable( (physLength >> KDiskSectorShift), (TUint8*) physAddr, err); sl@0: iSecondBuffer = EFalse; sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:rrb:%lx,%lx", aStart, aEnd)); sl@0: sl@0: __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(ERRBStAlign)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ERRBStPos)); sl@0: __ASSERT_DEBUG(aEnd > aStart, Panic(ERRBNotPositive)); sl@0: __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(ERRBEndAlign)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(ERRBEndPos)); sl@0: __ASSERT_DEBUG(!iDoDoubleBuffer, Panic(ENoDBSupport)); sl@0: __ASSERT_CACHE(CacheInvariant(), Panic(ERRBCchInv)); sl@0: __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ERRBExist)); sl@0: sl@0: TUint8* raby; sl@0: sl@0: BuildGammaArray(aStart, aEnd); sl@0: sl@0: // reposition start index at 0 if the full range would run off the end of the sl@0: // buffer. This is heuristic - enabling a longer multi-block may cost some sl@0: // cached reads. However, assume long reads do not generally re-read the same sl@0: // data, and are used for streaming large amounts of data into memory. sl@0: sl@0: const TInt blocksInRange = I64LOW((aEnd - aStart) >> iBlkLenLog2); sl@0: TInt startIndex = (iLstUsdCchEnt + 1) % iBlocksInBuffer; sl@0: if (startIndex + blocksInRange > iBlocksInBuffer) sl@0: startIndex = 0; sl@0: sl@0: // starting at startIndex, increase the range until it covers aEnd - aStart, sl@0: // or until the next block to read is available in the cache. sl@0: sl@0: TInt blkCnt = 0; sl@0: TBool finished; sl@0: do sl@0: { sl@0: finished = ( sl@0: // range allocated for entire read sl@0: blkCnt == blocksInRange sl@0: // next block already exists in buffer and has not been overwritten sl@0: // by existing multi-block read sl@0: || ( iGamma[blkCnt] != KNoCacheBlock sl@0: && ( iGamma[blkCnt] < startIndex sl@0: || iGamma[blkCnt] >= startIndex + blkCnt ) ) ); sl@0: sl@0: if (! finished) sl@0: ++blkCnt; sl@0: } while (! finished); sl@0: sl@0: iLstUsdCchEnt = startIndex + blkCnt - 1; sl@0: sl@0: if (blkCnt < 1) blkCnt = 1; //RBW required < 1 block to be read sl@0: sl@0: OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_RESERVEREADBLOCKS_RANGE, "blocksInRange=%d; blkCnt=%d", blocksInRange, blkCnt ); sl@0: sl@0: TUint32 lengthInBytes = blkCnt << iBlkLenLog2; sl@0: *aLength = lengthInBytes; sl@0: MarkBlocks(aStart, aStart + lengthInBytes, startIndex); sl@0: sl@0: raby = IdxToCchMem(startIndex); sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:rwb:%lx,%lx", aStart, aEnd)); sl@0: sl@0: TInt64 physStart = aStart & ~iBlkMsk; sl@0: TInt64 physEnd = (aEnd + iBlkMsk) & ~iBlkMsk; sl@0: sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > physStart, Panic(ERWBStPos)); sl@0: __ASSERT_DEBUG(aEnd > aStart, Panic(ERWBNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= physEnd, Panic(ERWBEndPos)); sl@0: __ASSERT_DEBUG(iDoPhysicalAddress || iDoDoubleBuffer || (!iDoDoubleBuffer && !iDoPhysicalAddress && physEnd - physStart <= (TInt64)iMaxBufSize), Panic(ERWBOverflow)); sl@0: __ASSERT_CACHE(CacheInvariant(), Panic(ERWBCchInv)); sl@0: sl@0: const TBool firstPartial = (aStart & iBlkMsk) != 0; sl@0: const TBool lastPartial = (aEnd & iBlkMsk) != 0; sl@0: sl@0: const TInt blkCnt = I64LOW((physEnd - physStart) >> iBlkLenLog2); sl@0: OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_RANGE, "blkCnt=%d", blkCnt ); sl@0: sl@0: TBool startUsed = EFalse; sl@0: TBool endUsed = EFalse; sl@0: sl@0: TUint8* raby = NULL; sl@0: sl@0: if(iDoDoubleBuffer) sl@0: { sl@0: // sl@0: // If we're double-buffering, then the entire cache will be re-used sl@0: // continuously. Rather than continually reserve blocks during each sl@0: // transfer we calculate the blocks that will be present after all sl@0: // transfers have completed. sl@0: // sl@0: InvalidateCache(); sl@0: raby = iCacheBuf; sl@0: } sl@0: else sl@0: { sl@0: TInt idx; sl@0: sl@0: // check if the first or last blocks are already in the buffer. sl@0: TInt fst = -1, lst = -1; sl@0: const TInt64 lstBlk = physEnd - iBlkLen; sl@0: TInt i; sl@0: for (i = 0; i < iBlocksInBuffer; ++i) sl@0: { sl@0: if (iCachedBlocks[i] == physStart) sl@0: fst = i; sl@0: sl@0: if (iCachedBlocks[i] == lstBlk) sl@0: lst = i; sl@0: } sl@0: sl@0: const TBool firstUsable = (fst != -1) && (iBlocksInBuffer - fst) >= blkCnt; sl@0: const TBool lastUsable = (lst != -1) && lst >= (blkCnt - 1); sl@0: sl@0: if (iDoPhysicalAddress) sl@0: { sl@0: if ( (firstPartial || lastPartial) && blkCnt <= 2) sl@0: { sl@0: //Physical addressing not to be used. sl@0: //more efficent to use local Cache copying sl@0: iDoPhysicalAddress = EFalse; sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_EXIT1, this, ( TUint )( raby ) ); sl@0: return raby; sl@0: } sl@0: else sl@0: { sl@0: raby = iMinorBuf; sl@0: sl@0: const TBool firstPres = (fst != -1); sl@0: const TBool lastPres = (lst != -1); sl@0: sl@0: if (firstPartial && firstPres) sl@0: { sl@0: // move to minor buffer sl@0: memcpy(iMinorBuf, IdxToCchMem(fst), iBlkLen); sl@0: } sl@0: if (lastPartial && lastPres) sl@0: { sl@0: // move to beginning of cache sl@0: memcpy(iCacheBuf, IdxToCchMem(lst), iBlkLen); sl@0: } sl@0: sl@0: InvalidateCache(physStart,physEnd); sl@0: sl@0: if (lastPartial) sl@0: { sl@0: //re-mark beginning of cache sl@0: MarkBlocks((physEnd-iBlkLen), physEnd, 0); sl@0: } sl@0: sl@0: if (aRBM) sl@0: { sl@0: *aRBM = 0; sl@0: sl@0: if (firstPartial) sl@0: *aRBM |= KWtMinFst; sl@0: sl@0: if (firstPartial && !firstPres) sl@0: *aRBM |= KWtRBMFst; sl@0: sl@0: if (lastPartial) sl@0: *aRBM |= KWtMinLst; sl@0: sl@0: if (lastPartial && !lastPres) sl@0: *aRBM |= KWtRBMLst; sl@0: } sl@0: sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_EXIT2, this, ( TUint )( raby ) ); sl@0: return raby; sl@0: } sl@0: } // if (iDoPhysicalAddress) sl@0: sl@0: if (!firstUsable && !lastUsable) sl@0: { sl@0: if(iDoDoubleBuffer) sl@0: { sl@0: idx = iSecondBuffer ? iBlocksInBuffer >> 1 : 0; sl@0: } sl@0: else sl@0: { sl@0: idx = (iLstUsdCchEnt + 1) % iBlocksInBuffer; sl@0: if (idx + blkCnt > iBlocksInBuffer) sl@0: idx = 0; sl@0: } sl@0: } sl@0: else if (firstUsable && ! lastUsable) sl@0: { sl@0: idx = fst; sl@0: } sl@0: else if (! firstUsable && lastUsable) sl@0: { sl@0: idx = lst - (blkCnt - 1); sl@0: } sl@0: else // (lastUsable && firstUsable) sl@0: { sl@0: if (firstPartial || ! lastPartial) sl@0: idx = fst; sl@0: else sl@0: idx = lst - (blkCnt - 1); sl@0: } sl@0: sl@0: MarkBlocks(physStart, physEnd, idx); sl@0: sl@0: // if the range started or ended on a partial block, but could not sl@0: // be allocated on that existing block, and the existing block is sl@0: // somewhere in the cache, then memcpy() that block to the end of the sl@0: // range. used is not the same as usable - both the start and end sl@0: // blocks may be usable, through not in the same range, or any range. sl@0: sl@0: const TInt startExtent = I64LOW(aStart & iBlkMsk); sl@0: TBool firstInTemp = EFalse; sl@0: startUsed = (idx == fst); sl@0: if (! startUsed && firstPartial && fst != -1) sl@0: { sl@0: // if the range has started at index occupied by the last block then sl@0: // temporarily copy to minor buffer. This is unnecessary when the sl@0: // last block is not partial because the last block does not need to sl@0: // be preserved. sl@0: sl@0: if (idx == lst && lastPartial) sl@0: { sl@0: firstInTemp = ETrue; sl@0: memcpy(iMinorBuf, IdxToCchMem(fst), startExtent); sl@0: } sl@0: else sl@0: { sl@0: memcpy(IdxToCchMem(idx), IdxToCchMem(fst), startExtent); sl@0: } sl@0: sl@0: startUsed = ETrue; sl@0: } sl@0: sl@0: endUsed = (idx + blkCnt - 1 == lst); sl@0: if (! endUsed && lastPartial && lst != -1) sl@0: { sl@0: const TInt endOffset = I64LOW(aEnd & iBlkMsk); sl@0: const TInt endExtent = iBlkLen - endOffset; sl@0: memcpy(IdxToCchMem(idx + blkCnt - 1) + endOffset, IdxToCchMem(lst) + endOffset, endExtent); sl@0: endUsed = ETrue; sl@0: } sl@0: sl@0: if (firstInTemp) sl@0: memcpy(IdxToCchMem(idx), iMinorBuf, startExtent); sl@0: sl@0: // start reclaiming at block following this range sl@0: iLstUsdCchEnt = idx + blkCnt - 1; sl@0: raby = IdxToCchMem(idx); sl@0: } sl@0: sl@0: // work out if read-before-write required sl@0: if (aRBM) sl@0: { sl@0: *aRBM = 0; sl@0: // first index was not already in range, and does not start on block boundary sl@0: if (firstPartial && ! startUsed) sl@0: *aRBM |= KWtRBMFst; sl@0: sl@0: // last index was not already in range, and does not end on block boundary sl@0: if (lastPartial && ! endUsed) sl@0: *aRBM |= KWtRBMLst; sl@0: sl@0: // only use one pre-read if contained in single block sl@0: if (blkCnt == 1 && *aRBM == (KWtRBMFst | KWtRBMLst)) sl@0: *aRBM = KWtRBMFst; sl@0: sl@0: // sl@0: // When double-buffering, RMW for the last block is stored in the sl@0: // minor buffer and writen during the last transfer, so flag this sl@0: // seperately (as aRBM is used for the initial RMW Read then subsequently cleared). sl@0: // sl@0: if(iDoDoubleBuffer && (*aRBM & KWtRBMLst)) sl@0: iDoLastRMW = ETrue; sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(" aStart, Panic(EMBStPos)); sl@0: __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(EMBStAlign)); sl@0: __ASSERT_DEBUG(aEnd > aStart, Panic(EMBNotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EMBEndPos)); sl@0: __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(EMBEndAlign)); sl@0: __ASSERT_DEBUG(aStartIndex + (TInt)((aEnd - aStart) >> iBlkLenLog2) <= iBlocksInBuffer, Panic(EMBOverflow)); sl@0: __ASSERT_CACHE(CacheInvariant(), Panic(EMBCchInvPre)); sl@0: sl@0: TInt i; sl@0: sl@0: for (i = 0; i < aStartIndex; ++i) sl@0: { sl@0: if (iCachedBlocks[i] >= aStart && iCachedBlocks[i] < aEnd) sl@0: iCachedBlocks[i] = KInvalidBlock; sl@0: } sl@0: sl@0: TInt blkCnt = I64LOW((aEnd - aStart) >> iBlkLenLog2); sl@0: OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_MARKBLOCKS_RANGE, "blkCnt=%d", blkCnt ); sl@0: for (i = aStartIndex; i < aStartIndex + blkCnt; ++i) sl@0: iCachedBlocks[i] = aStart + (static_cast(i - aStartIndex) << iBlkLenLog2); sl@0: sl@0: for (i = aStartIndex + blkCnt; i < iBlocksInBuffer; ++i) sl@0: { sl@0: if (iCachedBlocks[i] >= aStart && iCachedBlocks[i] < aEnd) sl@0: iCachedBlocks[i] = KInvalidBlock; sl@0: } sl@0: sl@0: __ASSERT_CACHE(CacheInvariant(), Panic(EMBCchInvPost)); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_MARKBLOCKS_EXIT, this ); sl@0: } sl@0: sl@0: sl@0: void DMmcMediaDriverFlash::BuildGammaArray(TInt64 aStart, TInt64 aEnd) sl@0: // sl@0: // iGamma is an array of indexes that correspond to cached blocks starting sl@0: // from aStart. iGamma[0] is the index of aStart, iGamma[1] is the index of sl@0: // aStart + iBlkLen, and so on. Building an array here means that all of sl@0: // the available cached entries can be found in linear time instead of sl@0: // quadratically searching through the array for each block. sl@0: // sl@0: { sl@0: OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:bga:%lx,%lx", aStart, aEnd)); sl@0: sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EBGAStPos)); sl@0: __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(EBGAStAlign)); sl@0: __ASSERT_DEBUG(aEnd > aStart, Panic(EBGANotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EBGAEndPos)); sl@0: __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(EBGAEndAlign)); sl@0: __ASSERT_DEBUG(aEnd - aStart <= (TInt64) iMaxBufSize, Panic(EBGAOverflow)); sl@0: __ASSERT_CACHE(CacheInvariant(), Panic(EBGACchInv)); sl@0: sl@0: // KNoCacheBlock = (0xff) x 4 sl@0: TUint blocksInRange = I64LOW((aEnd - aStart) >> iBlkLenLog2); sl@0: OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_RANGE, "blocksInRange=%d", blocksInRange ); sl@0: memset(iGamma, 0xff, sizeof(*iGamma) * blocksInRange); sl@0: sl@0: TInt64 blkAddr = 0; sl@0: for (TInt i = 0; ( (blocksInRange > 0 ) && (i < iBlocksInBuffer) ); ++i) sl@0: { sl@0: blkAddr = iCachedBlocks[i]; sl@0: if (blkAddr >= aStart && blkAddr < aEnd) sl@0: { sl@0: iGamma[I64LOW((blkAddr - aStart) >> iBlkLenLog2)] = i; sl@0: blocksInRange--; sl@0: } sl@0: } sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_EXIT, this ); sl@0: } sl@0: sl@0: void DMmcMediaDriverFlash::InvalidateCache() sl@0: { sl@0: OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_INVALIDATECACHE1_ENTRY ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ich")); sl@0: sl@0: // KInvalidBlock = (0xff) x 4 sl@0: memset(iCachedBlocks, 0xff, sizeof(*iCachedBlocks) * iBlocksInBuffer); sl@0: OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_INVALIDATECACHE1_EXIT ); sl@0: } sl@0: sl@0: // Invalidate any cache entries from aStart to aEnd sl@0: // This is for DMA writes and is to prevent the cache becoming inconsistent with the media. sl@0: void DMmcMediaDriverFlash::InvalidateCache(TInt64 aStart, TInt64 aEnd) sl@0: { sl@0: OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_INVALIDATECACHE2_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ich:%lx,%lx", aStart, aEnd)); sl@0: sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EBGAStPos)); sl@0: __ASSERT_DEBUG(aEnd > aStart, Panic(EBGANotPositive)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EBGAEndPos)); sl@0: sl@0: const TInt blkCnt = I64LOW((aStart - aEnd) >> iBlkLenLog2); sl@0: OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_INVALIDATECACHE_RANGE, "blocksInRange=%d", blkCnt ); sl@0: sl@0: __ASSERT_CACHE(CacheInvariant(), Panic(EBGACchInv)); sl@0: sl@0: TInt64 endBlk = (blkCnt == 0) ? (aStart+iBlkLen) : aEnd; sl@0: sl@0: for (TInt i = 0; i < iBlocksInBuffer; ++i) sl@0: { sl@0: const TInt64 blkAddr = iCachedBlocks[i]; sl@0: if (blkAddr >= aStart && blkAddr < endBlk) sl@0: iCachedBlocks[i] = KInvalidBlock; sl@0: } sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_INVALIDATECACHE2_EXIT, this ); sl@0: } sl@0: sl@0: TUint8* DMmcMediaDriverFlash::IdxToCchMem(TInt aIdx) const sl@0: { sl@0: OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_IDXTOCCHMEM_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:icm:%d", aIdx)); sl@0: sl@0: __ASSERT_DEBUG(aIdx >= 0, Panic(EICMNegative)); sl@0: __ASSERT_DEBUG(aIdx < iBlocksInBuffer, Panic(EICMOverflow)); sl@0: sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_IDXTOCCHMEM_EXIT, this ); sl@0: return &iCacheBuf[aIdx << iBlkLenLog2]; sl@0: } sl@0: sl@0: TInt DMmcMediaDriverFlash::CchMemToIdx(TUint8* aMemP) const sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CCHMEMTOIDX_ENTRY, this ); sl@0: __ASSERT_DEBUG((aMemP >= iCacheBuf) && (aMemP < iCacheBuf + (iBlocksInBuffer << iBlkLenLog2)), Panic(ECMIOverflow)); sl@0: sl@0: return((aMemP - iCacheBuf) >> iBlkLenLog2); sl@0: } sl@0: sl@0: #ifdef _DEBUG_CACHE sl@0: TBool DMmcMediaDriverFlash::CacheInvariant() sl@0: // sl@0: // check each cache entry refers to a valid block and that no two sl@0: // entries cover the same block. This algorithm is quadratic in sl@0: // the cache length. sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CACHEINVARIANT_ENTRY, this ); sl@0: for (TInt i = 0; i < iBlocksInBuffer; ++i) sl@0: { sl@0: if (iCachedBlocks[i] == KInvalidBlock) sl@0: continue; sl@0: sl@0: if ((iCachedBlocks[i] & iBlkMsk) != 0) sl@0: return EFalse; sl@0: sl@0: if (iCachedBlocks[i] >= TotalSizeInBytes()) sl@0: return EFalse; sl@0: sl@0: for (TInt j = i + 1; j < iBlocksInBuffer; ++j) sl@0: { sl@0: if (iCachedBlocks[i] == iCachedBlocks[j]) sl@0: return EFalse; sl@0: } sl@0: } sl@0: sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_CACHEINVARIANT_EXIT, this ); sl@0: return ETrue; sl@0: } sl@0: #endif sl@0: sl@0: void DMmcMediaDriverFlash::NotifyPowerDown() sl@0: { sl@0: OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_NOTIFYPOWERDOWN_ENTRY ); sl@0: __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Mmc:NotifyPowerDown")); sl@0: sl@0: iSessionEndDfc.Cancel(); sl@0: iDataTransferCallBackDfc.Cancel(); sl@0: sl@0: EndInCritical(); sl@0: sl@0: // need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once. sl@0: if (iSession) sl@0: iStack->CancelSession(iSession); sl@0: sl@0: CompleteRequest(KErrNotReady); sl@0: iMedReq = EMReqIdle; sl@0: OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_NOTIFYPOWERDOWN_EXIT ); sl@0: } sl@0: sl@0: void DMmcMediaDriverFlash::NotifyEmergencyPowerDown() sl@0: { sl@0: OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_NOTIFYEMERGENCYPOWERDOWN_ENTRY ); sl@0: __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NotifyEmergencyPowerDown")); sl@0: sl@0: iSessionEndDfc.Cancel(); sl@0: iDataTransferCallBackDfc.Cancel(); sl@0: sl@0: TInt r=KErrNotReady; sl@0: if (iCritical) sl@0: r=KErrAbort; sl@0: EndInCritical(); sl@0: sl@0: // need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once. sl@0: if (iSession) sl@0: iStack->CancelSession(iSession); sl@0: sl@0: CompleteRequest(r); sl@0: iMedReq = EMReqIdle; sl@0: OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_NOTIFYEMERGENCYPOWERDOWN_EXIT ); sl@0: } sl@0: sl@0: TInt DMmcMediaDriverFlash::Request(TLocDrvRequest& aRequest) sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_REQUEST_ENTRY, this ); sl@0: __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x id %d",&aRequest,aRequest.Id())); sl@0: TInt r=KErrNotSupported; sl@0: TInt id=aRequest.Id(); sl@0: OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_ID, "Request=0x%08x; Request ID=%d", (TUint) &aRequest, id); sl@0: sl@0: #if defined (__TEST_PAGING_MEDIA_DRIVER__) sl@0: DThread* client=aRequest.Client(); sl@0: __KTRACE_OPT(KLOCDPAGING,Kern::Printf("Client:0x%08x",client)); sl@0: OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_CLIENT, "Request client=0x%08x", (TUint) client); sl@0: #endif // __TEST_PAGING_MEDIA_DRIVER__ sl@0: sl@0: // First handle requests that can be handled without deferring sl@0: if(id==DLocalDrive::ECaps) sl@0: { sl@0: TLocalDriveCapsV6& c = *(TLocalDriveCapsV6*)aRequest.RemoteDes(); sl@0: TLocDrv& drive = *aRequest.Drive(); sl@0: r = Caps(drive, c); sl@0: c.iSize = drive.iPartitionLen; sl@0: c.iPartitionType = drive.iPartitionType; sl@0: c.iHiddenSectors = (TUint) (drive.iPartitionBaseAddr >> KDiskSectorShift); sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT1, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: // All other requests must be deferred if a request is currently in progress sl@0: if (iCurrentReq) sl@0: { sl@0: sl@0: #if defined(__TEST_PAGING_MEDIA_DRIVER__) sl@0: if (DMediaPagingDevice::PageInRequest(*iCurrentReq)) sl@0: iMmcStats.iReqPage++; sl@0: else sl@0: iMmcStats.iReqNormal++; sl@0: #endif // __TEST_PAGING_MEDIA_DRIVER__ sl@0: sl@0: // a request is already in progress, so hold on to this one sl@0: __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x ret 1",&aRequest)); sl@0: OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_IN_PROGRESS, "Request in progress=0x%08x", (TUint) &aRequest); sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT2, this, KMediaDriverDeferRequest ); sl@0: return KMediaDriverDeferRequest; sl@0: } sl@0: else sl@0: { sl@0: iCurrentReq=&aRequest; sl@0: TUint partitionType = iCurrentReq->Drive()->iPartitionType; sl@0: TBool readOnly = (partitionType == KPartitionTypeRofs || partitionType == KPartitionTypeROM); sl@0: sl@0: switch (id) sl@0: { sl@0: sl@0: sl@0: #if defined(__DEMAND_PAGING__) sl@0: case DMediaPagingDevice::ERomPageInRequest: sl@0: __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Request(ERomPageInRequest)")); sl@0: BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_MMC,iCurrentReq); sl@0: OstTraceDef0( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_ROM_PAGE_IN, "ROM page-in request"); sl@0: r=DoRead(); sl@0: break; sl@0: case DMediaPagingDevice::ECodePageInRequest: sl@0: __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Request(ECodePageInRequest)")); sl@0: BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_MMC,iCurrentReq); sl@0: OstTraceDef0( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_CODE_PAGE_IN, "Code page-in request"); sl@0: r=DoRead(); sl@0: break; sl@0: #endif // __DEMAND_PAGING__ sl@0: sl@0: case DLocalDrive::EQueryDevice: sl@0: r = KErrNotSupported; sl@0: break; sl@0: sl@0: case DLocalDrive::ERead: sl@0: r=DoRead(); sl@0: break; sl@0: case DLocalDrive::EWrite: sl@0: if (readOnly) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT3, this, KErrNotSupported ); sl@0: return KErrNotSupported; sl@0: } sl@0: r=DoWrite(); sl@0: break; sl@0: case DLocalDrive::EFormat: sl@0: if (readOnly) sl@0: { sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT4, this, KErrNotSupported ); sl@0: return KErrNotSupported; sl@0: } sl@0: r=DoFormat(); sl@0: break; sl@0: sl@0: #if defined __TEST_PAGING_MEDIA_DRIVER__ sl@0: case DLocalDrive::EControlIO: sl@0: { sl@0: r = HandleControlIORequest(); sl@0: break; sl@0: } sl@0: #endif sl@0: sl@0: case DLocalDrive::EPasswordUnlock: sl@0: case DLocalDrive::EPasswordLock: sl@0: case DLocalDrive::EPasswordClear: sl@0: // Don't allow passords on internal MMC; one reason is that this may be used for paging and sl@0: // we can't really stop paging just because the password hasn't been supplied sl@0: if (iInternalSlot) sl@0: r = KErrNotSupported; sl@0: else sl@0: r = DoPasswordOp(); sl@0: break; sl@0: case DLocalDrive::EPasswordErase: sl@0: { sl@0: r = LaunchRPIErase(); sl@0: // This will complete the request in the event of an error sl@0: if(r != KErrNone) sl@0: PartitionInfoComplete(r); sl@0: sl@0: r = KErrNone; // ensures to indicate asynchronoous completion sl@0: break; sl@0: } sl@0: case DLocalDrive::EWritePasswordStore: sl@0: { sl@0: // sl@0: // If the card is ready and locked, request the stack to perform the sl@0: // auto-unlock sequence. This is required, as the stack only performs sl@0: // automatic unlocking during power-up, and the stack may already be powered. sl@0: // sl@0: r = KErrNone; // asynchronous completion sl@0: sl@0: if(iCard->IsReady() && iCard->IsLocked()) sl@0: { sl@0: iSession->SetupCIMAutoUnlock(); sl@0: if(EngageAndSetRequest(EMReqWritePasswordData, 0) != KErrNone) sl@0: { sl@0: // If error, complete with KErrNone anyway sl@0: // - The password store has been set, any errors sl@0: // will be reported on the next access. sl@0: CompleteRequest(KErrNone); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: CompleteRequest(KErrNone); sl@0: } sl@0: break; sl@0: } sl@0: case DLocalDrive::EEnlarge: sl@0: case DLocalDrive::EReduce: sl@0: default: sl@0: r=KErrNotSupported; sl@0: break; sl@0: } sl@0: } sl@0: sl@0: __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x cmp %d",&aRequest,r)); sl@0: sl@0: if (r != KErrNone) sl@0: { sl@0: iMedReq = EMReqIdle; sl@0: iCurrentReq=NULL; sl@0: SetCurrentConsumption(KIdleCurrentInMilliAmps); sl@0: } sl@0: sl@0: OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT5, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: void DMmcMediaDriverFlash::Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg) sl@0: { sl@0: OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DISCONNECT_ENTRY, this ); sl@0: // Complete using the default implementation sl@0: DMediaDriver::Disconnect(aLocalDrive, aMsg); sl@0: OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DISCONNECT_EXIT, this ); sl@0: } sl@0: sl@0: #ifdef _DEBUG_CACHE sl@0: TUint8* DMmcMediaDriverFlash::GetCachedBlock(TInt64 aMdAddr) sl@0: // sl@0: // return cache block for media at aMdAddr, 0 if not found. sl@0: // This is a debug function to determine whether or not a block is in sl@0: // the cache. It should not be used for general block retrieval. sl@0: // If there are m blocks in the cache, and n in the requested range, sl@0: // this function is o(mn), whereas BuildGammaArray() is theta(m). sl@0: // sl@0: { sl@0: OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_GETCACHEDBLOCK_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:gcb:%lx", aMdAddr)); sl@0: sl@0: __ASSERT_DEBUG((aMdAddr & iBlkMsk) == 0, Panic(EGCBAlign)); sl@0: __ASSERT_DEBUG(TotalSizeInBytes() > aMdAddr, Panic(EGCBPos)); sl@0: __ASSERT_CACHE(CacheInvariant(), Panic(EGCBCchInv)); sl@0: sl@0: for (TInt i = 0; i < iBlocksInBuffer; ++i) sl@0: { sl@0: if (iCachedBlocks[i] == aMdAddr) sl@0: { sl@0: TUint8* raby = IdxToCchMem(i); sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Int0(); sl@0: TAny* aParam1 = iCurrentReq->Ptr1(); sl@0: // TAny* aParam2 = iCurrentReq->Ptr2(); sl@0: sl@0: TInt r = KErrCompletion; sl@0: sl@0: __KTRACE_OPT(KLOCDPAGING,Kern::Printf("[MD : ] HandleControlIORequest aCommand: 0x%x", command)); sl@0: sl@0: sl@0: switch (command) sl@0: { sl@0: case KMmcGetStats: sl@0: { sl@0: DThread* pC = iCurrentReq->Client(); sl@0: DThread* pT = iCurrentReq->RemoteThread(); sl@0: if (!pT) sl@0: pT = pC; sl@0: Kern::ThreadRawWrite(pT, aParam1, &iMmcStats, sizeof(iMmcStats), pC); sl@0: sl@0: iMmcStats.iReqNormal=0; sl@0: iMmcStats.iNormalFragmenting=0; sl@0: iMmcStats.iClashFragmenting=0; sl@0: sl@0: break; sl@0: } sl@0: default: sl@0: r=KErrNotSupported; sl@0: break; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: #endif // __TEST_PAGING_MEDIA_DRIVER__ sl@0: sl@0: sl@0: sl@0: sl@0: DECLARE_EXTENSION_PDD() sl@0: { sl@0: // NB if the media driver has been defined as a kernel extension in the .OBY/.IBY file sl@0: // i.e the "extension" keyword has been used rather than "device", then an instance of sl@0: // DPhysicalDeviceMediaMmcFlash will already have been created by InitExtension(). In this sl@0: // case the kernel will see that an object of the same name already exists and delete the sl@0: // new one. sl@0: return new DPhysicalDeviceMediaMmcFlash; sl@0: } sl@0: DECLARE_STANDARD_EXTENSION() sl@0: { sl@0: __KTRACE_OPT(KBOOT,Kern::Printf("Creating MMCDrv PDD")); sl@0: sl@0: DPhysicalDeviceMediaMmcFlash* device = new DPhysicalDeviceMediaMmcFlash; sl@0: sl@0: TInt r; sl@0: if (device==NULL) sl@0: r=KErrNoMemory; sl@0: else sl@0: r=Kern::InstallPhysicalDevice(device); sl@0: __KTRACE_OPT(KBOOT,Kern::Printf("Installing MMCDrv PDD in kernel returned %d",r)); sl@0: sl@0: __KTRACE_OPT(KBOOT,Kern::Printf("Mmc extension entry point drive returns %d",r)); sl@0: return r; sl@0: } sl@0: sl@0: