diff -r 000000000000 -r 96e5fb8b040d kernel/eka/drivers/medmmc/emmcptn.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/medmmc/emmcptn.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,313 @@ +// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Partition Management for Embedded MMC devices +// +// + +#include + +const TInt KDiskSectorShift=9; + +class DLegacyEMMCPartitionInfo : public DEMMCPartitionInfo + { +public: + DLegacyEMMCPartitionInfo(); + ~DLegacyEMMCPartitionInfo(); +public: + virtual TInt Initialise(DMediaDriver* aDriver); + virtual TInt PartitionInfo(TPartitionInfo& anInfo, const TMMCCallBack& aCallBack); + virtual TInt PartitionCaps(TLocDrv& aDrive, TDes8& aInfo); + +protected: + void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors); + +private: + static void SessionEndCallBack(TAny* aSelf); + void DoSessionEndCallBack(); + virtual TInt DecodePartitionInfo(); + +protected: + DMediaDriver* iDriver; + TPartitionInfo* iPartitionInfo; + TMMCCallBack iSessionEndCallBack; + TMMCCallBack iCallBack; // Where to report the PartitionInfo completion + DMMCSession* iSession; + TMMCard* iCard; + TUint8* iIntBuf; + }; + +DLegacyEMMCPartitionInfo::DLegacyEMMCPartitionInfo() + : iSessionEndCallBack(DLegacyEMMCPartitionInfo::SessionEndCallBack, this) + { + } + +DLegacyEMMCPartitionInfo::~DLegacyEMMCPartitionInfo() + { + delete iSession; + } + +TInt DLegacyEMMCPartitionInfo::Initialise(DMediaDriver* aDriver) + { + iDriver = aDriver; + + DMMCSocket* socket = ((DMMCSocket*)((DPBusPrimaryMedia*)(iDriver->iPrimaryMedia))->iSocket); + if(socket == NULL) + return(KErrNoMemory); + + DMMCStack* stack = socket->Stack(0); + iCard = stack->CardP(((DPBusPrimaryMedia*)(iDriver->iPrimaryMedia))->iSlotNumber); + + iSession = stack->AllocSession(iSessionEndCallBack); + if (iSession == NULL) + return(KErrNoMemory); + + iSession->SetStack(stack); + iSession->SetCard(iCard); + + // this gets used before any access + TInt bufLen, minorBufLen; + stack->BufferInfo(iIntBuf, bufLen, minorBufLen); + + return(KErrNone); + } + +TInt DLegacyEMMCPartitionInfo::PartitionInfo(TPartitionInfo& anInfo, const TMMCCallBack& aCallBack) + { + iPartitionInfo = &anInfo; + iCallBack = aCallBack; + // If media driver is persistent (see EMediaDriverPersistent), + // the card may have changed since last power down, so reset CID + iSession->SetCard(iCard); + + iSession->SetupCIMReadBlock(0, iIntBuf); + + TInt r = iDriver->InCritical(); + if (r == KErrNone) + r = iSession->Engage(); + + if(r != KErrNone) + iDriver->EndInCritical(); + + return(r); + } + +TInt DLegacyEMMCPartitionInfo::PartitionCaps(TLocDrv& aDrive, TDes8& aInfo) + { + TLocalDriveCapsV6Buf& Info = static_cast< TLocalDriveCapsV6Buf&> (aInfo); + + // is this query for the swap partition ? + if (aDrive.iPartitionType == KPartitionTypePagedData) + { + Info().iFileSystemId = KDriveFileNone; + Info().iDriveAtt|= KDriveAttHidden; + } + + // is this query for the ROFS partition ? + if (aDrive.iPartitionType == KPartitionTypeRofs) + { + Info().iFileSystemId = KDriveFileSysROFS; + Info().iMediaAtt&= ~KMediaAttFormattable; + Info().iMediaAtt|= KMediaAttWriteProtected; + } + + // is this query for the ROM partition ? + if (aDrive.iPartitionType == KPartitionTypeROM) + { + Info().iFileSystemId = KDriveFileNone; + Info().iMediaAtt&= ~KMediaAttFormattable; + Info().iMediaAtt|= KMediaAttWriteProtected; + } + + return KErrNone; + } + +void DLegacyEMMCPartitionInfo::SessionEndCallBack(TAny* aSelf) + { + DLegacyEMMCPartitionInfo& self = *static_cast(aSelf); + self.DoSessionEndCallBack(); + } + +void DLegacyEMMCPartitionInfo::DoSessionEndCallBack() + { + iDriver->EndInCritical(); + + TInt r = iSession->EpocErrorCode(); + + if (r == KErrNone) + r = DecodePartitionInfo(); + + iDriver->PartitionInfoComplete(r == KErrNone ? r : KErrNotReady); + } + +TInt DLegacyEMMCPartitionInfo::DecodePartitionInfo() +// +// decode partition info that was read into internal buffer +// + { + TUint partitionCount=iPartitionInfo->iPartitionCount=0; + TInt defaultPartitionNumber=-1; + TMBRPartitionEntry* pe; + const TUint KMBRFirstPartitionOffsetAligned = KMBRFirstPartitionOffset & ~3; + TInt i; + + // Read of the first sector successful so check for a Master Boot Record + if (*(TUint16*)(&iIntBuf[KMBRSignatureOffset])!=0xAA55) + // If no valid signature give up now, No way to re-format an internal drive correctly + return KErrCorrupt; + + __ASSERT_COMPILE(KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry) <= KMBRSignatureOffset); + + memmove(&iIntBuf[0], &iIntBuf[2], + KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry)); + + + for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]); + pe->iPartitionType != 0 && i < KMaxPartitionEntries; i++,pe--) + { + if (pe->IsDefaultBootPartition()) + { + SetPartitionEntry(&iPartitionInfo->iEntry[0],pe->iFirstSector,pe->iNumSectors); + defaultPartitionNumber=i; + partitionCount++; + break; + } + } + + // Now add any other partitions + for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]); + pe->iPartitionType != 0 && i < KMaxPartitionEntries; i++,pe--) + { + if (defaultPartitionNumber==i) + { + // Already sorted + } + + // FAT partition ? + else if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition()) + { + SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); + __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: FAT partition found at sector #%u", pe->iFirstSector)); + partitionCount++; + } + + else if (pe->iPartitionType == KPartitionTypeROM) + { + TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount]; + SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); + partitionEntry.iPartitionType = pe->iPartitionType; + partitionCount++; + + __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypeROM found at sector #%u", pe->iFirstSector)); + } + + // ROFS partition ? + else if (pe->iPartitionType == KPartitionTypeRofs) + { + +// Don't expose this for normal operation only boot? + TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount]; + SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); + partitionEntry.iPartitionType = pe->iPartitionType; + __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypeRofs found at sector #%u", pe->iFirstSector)); + partitionCount++; + } + + // Swap partition ? + else if (pe->iPartitionType == KPartitionTypePagedData) + { + __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypePagedData found at sector #%u", pe->iFirstSector)); + + TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount]; + SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); + partitionEntry.iPartitionType = pe->iPartitionType; + partitionCount++; + } + } + + // Check the validity of the partition address boundaries + // If there is any MBR errors + if(partitionCount > 0) + { + const TInt64 deviceSize = iCard->DeviceSize64(); + TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1]; + // Check that the card address space boundary is not exceeded by the last partition + if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize) + { + __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space")); + return KErrCorrupt; + } + + // More than one partition. Go through all of them + if (partitionCount > 0) + { + for(i=partitionCount-1; i>0; i--) + { + const TPartitionEntry& curr = iPartitionInfo->iEntry[i]; + TPartitionEntry& prev = iPartitionInfo->iEntry[i-1]; + // Check if partitions overlap + if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen)) + { + __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Overlapping partitions")); + return KErrCorrupt; + } + } + } + } + + if (defaultPartitionNumber==(-1) && partitionCount==0) + { + __KTRACE_OPT(KPBUSDRV, Kern::Printf("No Valid Partitions Found!")); + return KErrCorrupt; + } + + iPartitionInfo->iPartitionCount=partitionCount; + iPartitionInfo->iMediaSizeInBytes=iCard->DeviceSize64(); + +#ifdef _DEBUG + __KTRACE_OPT(KPBUSDRV, Kern::Printf("iEntry[x].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[x].iPartitionLen))); +#endif + + //Notify medmmc that partitioninfo is complete. + iCallBack.CallBack(); + + return(KErrNone); + } + + +void DLegacyEMMCPartitionInfo::SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors) +// +// auxiliary static function to record partition information in TPartitionEntry object +// + { + aEntry->iPartitionBaseAddr=aFirstSector; + aEntry->iPartitionBaseAddr<<=KDiskSectorShift; + aEntry->iPartitionLen=aNumSectors; + aEntry->iPartitionLen<<=KDiskSectorShift; + aEntry->iPartitionType=KPartitionTypeFAT12; + } + +// End - DLegacyEMMCPartitionInfo + + +EXPORT_C DEMMCPartitionInfo* CreateEmmcPartitionInfo() + { + return new DLegacyEMMCPartitionInfo; + } + +DECLARE_STANDARD_EXTENSION() + { + return KErrNone; + }