sl@0: // Copyright (c) 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: // Partition Management for Embedded MMC devices sl@0: // sl@0: // sl@0: sl@0: #include 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 "emmcptnTraces.h" sl@0: #endif sl@0: sl@0: sl@0: const TInt KDiskSectorShift=9; sl@0: sl@0: class DLegacyEMMCPartitionInfo : public DEMMCPartitionInfo sl@0: { sl@0: public: sl@0: DLegacyEMMCPartitionInfo(); sl@0: ~DLegacyEMMCPartitionInfo(); sl@0: public: sl@0: virtual TInt Initialise(DMediaDriver* aDriver); sl@0: virtual TInt PartitionInfo(TPartitionInfo& anInfo, const TMMCCallBack& aCallBack); sl@0: virtual TInt PartitionCaps(TLocDrv& aDrive, TDes8& aInfo); sl@0: sl@0: protected: sl@0: void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors); sl@0: sl@0: private: sl@0: static void SessionEndCallBack(TAny* aSelf); sl@0: void DoSessionEndCallBack(); sl@0: virtual TInt DecodePartitionInfo(); sl@0: sl@0: protected: sl@0: DMediaDriver* iDriver; sl@0: TPartitionInfo* iPartitionInfo; sl@0: TMMCCallBack iSessionEndCallBack; sl@0: TMMCCallBack iCallBack; // Where to report the PartitionInfo completion sl@0: DMMCSession* iSession; sl@0: TMMCard* iCard; sl@0: TUint8* iIntBuf; sl@0: }; sl@0: sl@0: DLegacyEMMCPartitionInfo::DLegacyEMMCPartitionInfo() sl@0: : iSessionEndCallBack(DLegacyEMMCPartitionInfo::SessionEndCallBack, this) sl@0: { sl@0: OstTraceFunctionEntry0( DLEGACYEMMCPARTITIONINFO_DLEGACYEMMCPARTITIONINFO_ENTRY ); sl@0: } sl@0: sl@0: DLegacyEMMCPartitionInfo::~DLegacyEMMCPartitionInfo() sl@0: { sl@0: OstTraceFunctionEntry0( DLEGACYEMMCPARTITIONINFO_DESTRUCTOR_ENTRY ); sl@0: delete iSession; sl@0: OstTraceFunctionExit0( DLEGACYEMMCPARTITIONINFO_DESTRUCTOR_EXIT ); sl@0: } sl@0: sl@0: TInt DLegacyEMMCPartitionInfo::Initialise(DMediaDriver* aDriver) sl@0: { sl@0: OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_INITIALISE_ENTRY, this ); sl@0: iDriver = aDriver; sl@0: sl@0: DMMCSocket* socket = ((DMMCSocket*)((DPBusPrimaryMedia*)(iDriver->iPrimaryMedia))->iSocket); sl@0: if(socket == NULL) sl@0: { sl@0: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_INITIALISE_EXIT1, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: DMMCStack* stack = socket->Stack(0); sl@0: iCard = stack->CardP(((DPBusPrimaryMedia*)(iDriver->iPrimaryMedia))->iSlotNumber); sl@0: sl@0: iSession = stack->AllocSession(iSessionEndCallBack); sl@0: if (iSession == NULL) sl@0: return KErrNoMemory; sl@0: sl@0: iSession->SetStack(stack); sl@0: iSession->SetCard(iCard); sl@0: sl@0: // this gets used before any access sl@0: TInt bufLen, minorBufLen; sl@0: stack->BufferInfo(iIntBuf, bufLen, minorBufLen); sl@0: sl@0: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_INITIALISE_EXIT2, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DLegacyEMMCPartitionInfo::PartitionInfo(TPartitionInfo& anInfo, const TMMCCallBack& aCallBack) sl@0: { sl@0: OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_PARTITIONINFO_ENTRY, this ); sl@0: iPartitionInfo = &anInfo; sl@0: iCallBack = aCallBack; 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: iSession->SetupCIMReadBlock(0, iIntBuf); sl@0: sl@0: TInt r = iDriver->InCritical(); sl@0: if (r == KErrNone) sl@0: r = iSession->Engage(); sl@0: sl@0: if(r != KErrNone) sl@0: iDriver->EndInCritical(); sl@0: sl@0: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_PARTITIONINFO_EXIT, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: TInt DLegacyEMMCPartitionInfo::PartitionCaps(TLocDrv& aDrive, TDes8& aInfo) sl@0: { sl@0: OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_PARTITIONCAPS_ENTRY, this ); sl@0: TLocalDriveCapsV6Buf& Info = static_cast< TLocalDriveCapsV6Buf&> (aInfo); sl@0: sl@0: // is this query for the swap partition ? sl@0: if (aDrive.iPartitionType == KPartitionTypePagedData) sl@0: { sl@0: Info().iFileSystemId = KDriveFileNone; sl@0: Info().iDriveAtt|= KDriveAttHidden; sl@0: } sl@0: sl@0: // is this query for the ROFS partition ? sl@0: if (aDrive.iPartitionType == KPartitionTypeRofs) sl@0: { sl@0: Info().iFileSystemId = KDriveFileSysROFS; sl@0: Info().iMediaAtt&= ~KMediaAttFormattable; sl@0: Info().iMediaAtt|= KMediaAttWriteProtected; sl@0: } sl@0: sl@0: // is this query for the ROM partition ? sl@0: if (aDrive.iPartitionType == KPartitionTypeROM) sl@0: { sl@0: Info().iFileSystemId = KDriveFileNone; sl@0: Info().iMediaAtt&= ~KMediaAttFormattable; sl@0: Info().iMediaAtt|= KMediaAttWriteProtected; sl@0: } sl@0: sl@0: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_PARTITIONCAPS_EXIT, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DLegacyEMMCPartitionInfo::SessionEndCallBack(TAny* aSelf) sl@0: { sl@0: OstTraceFunctionEntry0( DLEGACYEMMCPARTITIONINFO_SESSIONENDCALLBACK_ENTRY ); sl@0: DLegacyEMMCPartitionInfo& self = *static_cast(aSelf); sl@0: self.DoSessionEndCallBack(); sl@0: OstTraceFunctionExit0( DLEGACYEMMCPARTITIONINFO_SESSIONENDCALLBACK_EXIT ); sl@0: } sl@0: sl@0: void DLegacyEMMCPartitionInfo::DoSessionEndCallBack() sl@0: { sl@0: OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_DOSESSIONENDCALLBACK_ENTRY, this ); sl@0: iDriver->EndInCritical(); sl@0: sl@0: TInt r = iSession->EpocErrorCode(); sl@0: sl@0: if (r == KErrNone) sl@0: r = DecodePartitionInfo(); sl@0: sl@0: iDriver->PartitionInfoComplete(r == KErrNone ? r : KErrNotReady); sl@0: OstTraceFunctionExit1( DLEGACYEMMCPARTITIONINFO_DOSESSIONENDCALLBACK_EXIT, this ); sl@0: } sl@0: sl@0: TInt DLegacyEMMCPartitionInfo::DecodePartitionInfo() sl@0: // sl@0: // decode partition info that was read into internal buffer sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_ENTRY, this ); sl@0: TUint partitionCount=iPartitionInfo->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: { sl@0: // If no valid signature give up now, No way to re-format an internal drive correctly sl@0: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT1, this, KErrCorrupt ); sl@0: return KErrCorrupt; sl@0: } 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 < KMaxPartitionEntries; 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 < KMaxPartitionEntries; i++,pe--) 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, DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_FAT, "FAT partition found at sector #%x", pe->iFirstSector); sl@0: partitionCount++; sl@0: } sl@0: sl@0: else if (pe->iPartitionType == KPartitionTypeROM) sl@0: { sl@0: TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount]; sl@0: SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); sl@0: partitionEntry.iPartitionType = pe->iPartitionType; sl@0: partitionCount++; sl@0: sl@0: __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypeROM found at sector #%u", pe->iFirstSector)); sl@0: OstTrace1(TRACE_INTERNALS, DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_ROM, "KPartitionTypeROM found at sector #%x", pe->iFirstSector); sl@0: } sl@0: sl@0: // ROFS partition ? sl@0: else if (pe->iPartitionType == KPartitionTypeRofs) sl@0: { sl@0: sl@0: // Don't expose this for normal operation only boot? sl@0: TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount]; sl@0: SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); sl@0: partitionEntry.iPartitionType = pe->iPartitionType; sl@0: __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypeRofs found at sector #%u", pe->iFirstSector)); sl@0: OstTrace1(TRACE_INTERNALS, DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_ROFS, "KPartitionTypeRofs found at sector #%x", pe->iFirstSector); sl@0: partitionCount++; sl@0: } sl@0: sl@0: // Swap partition ? sl@0: else if (pe->iPartitionType == KPartitionTypePagedData) sl@0: { sl@0: __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypePagedData found at sector #%u", pe->iFirstSector)); sl@0: OstTrace1(TRACE_INTERNALS, DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_PAGED, "KPartitionTypeRofs found at sector #%x", pe->iFirstSector); sl@0: TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount]; sl@0: SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); sl@0: partitionEntry.iPartitionType = pe->iPartitionType; sl@0: partitionCount++; sl@0: } sl@0: } sl@0: sl@0: // Check the validity of the partition address boundaries sl@0: // If there is any MBR errors 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: if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space")); sl@0: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT2, this, KErrCorrupt ); sl@0: return KErrCorrupt; 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: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT3, this, KErrCorrupt ); sl@0: return KErrCorrupt; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (defaultPartitionNumber==(-1) && partitionCount==0) sl@0: { sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("No Valid Partitions Found!")); sl@0: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT4, this, KErrCorrupt ); sl@0: return KErrCorrupt; sl@0: } sl@0: sl@0: iPartitionInfo->iPartitionCount=partitionCount; sl@0: iPartitionInfo->iMediaSizeInBytes=iCard->DeviceSize64(); sl@0: sl@0: #ifdef _DEBUG sl@0: __KTRACE_OPT(KPBUSDRV, Kern::Printf("iEntry[x].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[x].iPartitionLen))); sl@0: #endif sl@0: sl@0: //Notify medmmc that partitioninfo is complete. sl@0: iCallBack.CallBack(); sl@0: sl@0: OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT5, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: void DLegacyEMMCPartitionInfo::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: OstTraceFunctionEntryExt( DLEGACYEMMCPARTITIONINFO_SETPARTITIONENTRY_ENTRY, this ); 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: OstTraceFunctionExit1( DLEGACYEMMCPARTITIONINFO_SETPARTITIONENTRY_EXIT, this ); sl@0: } sl@0: sl@0: // End - DLegacyEMMCPartitionInfo sl@0: sl@0: sl@0: EXPORT_C DEMMCPartitionInfo* CreateEmmcPartitionInfo() sl@0: { sl@0: OstTraceFunctionEntry0( _CREATEEMMCPARTITIONINFO_ENTRY ); sl@0: return new DLegacyEMMCPartitionInfo; sl@0: } sl@0: sl@0: DECLARE_STANDARD_EXTENSION() sl@0: { sl@0: return KErrNone; sl@0: }