kernel/eka/drivers/medmmc/emmcptn.cpp
changeset 0 a41df078684a
child 33 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/medmmc/emmcptn.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -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 <drivers/emmcptn.h>
+
+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<DLegacyEMMCPartitionInfo*>(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("<Mmc:PartitionInfo (C:%d)",partitionCount));
+	for (TUint x=0; x<partitionCount; x++)
+		__KTRACE_OPT(KPBUSDRV, Kern::Printf("     Partition%d (B:%xH L:%xH)",x,I64LOW(iPartitionInfo->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;
+	}