kernel/eka/drivers/medmmc/bgahsmmcptn.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 15 2d65c2f76d7b
child 19 4a8fed1c0ef6
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Partition Management for Embedded MMC devices
//
//

#include <emmcptn.h>
#include "bgahsmmcptn.h"

const TInt	  KDiskSectorShift		= 9;
const TUint32 KPIOffsetFromMediaEnd = 1;

class DBB5PartitionInfo : public DEMMCPartitionInfo
	{
public:
	 DBB5PartitionInfo();
	~DBB5PartitionInfo();

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;
	TUint32 		iPartitionAttributes[KMaxLocalDrives];
	};

DBB5PartitionInfo::DBB5PartitionInfo()
  : iSessionEndCallBack(DBB5PartitionInfo::SessionEndCallBack, this)
	{
	}

DBB5PartitionInfo::~DBB5PartitionInfo()
	{
	delete iSession;
	}

TInt DBB5PartitionInfo::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 DBB5PartitionInfo::PartitionInfo(TPartitionInfo& aInfo, const TMMCCallBack& aCallBack)
	{
	iPartitionInfo = &aInfo;
	iCallBack = aCallBack;

	// If media driver is persistent (see EMediaDriverPersistent)
	// the card may have changed since last power down, so reset CID
	iSession->SetCard(iCard);

	const TUint32 ptiOffset = (I64LOW(iCard->DeviceSize64() >> KDiskSectorShift)) - KPIOffsetFromMediaEnd;
	iSession->SetupCIMReadBlock(ptiOffset, iIntBuf);

	TInt r = iDriver->InCritical();
	if (r == KErrNone)
		r = iSession->Engage();

	if(r != KErrNone)
		iDriver->EndInCritical();

	return(r);
	}

TInt DBB5PartitionInfo::PartitionCaps(TLocDrv& aDrive, TDes8& aInfo)
	{
	TLocalDriveCapsV6Buf& Info = static_cast< TLocalDriveCapsV6Buf&> (aInfo);

	if (aDrive.iPartitionType == KPartitionTypePagedData)
		{
		Info().iFileSystemId = KDriveFileNone;
		Info().iDriveAtt |= KDriveAttHidden;
		}
	else if ( PartitionIsFAT(aDrive.iPartitionType) || PartitionIsFAT32(aDrive.iPartitionType)	)
		{		
		Info().iDriveAtt = iPartitionAttributes[aDrive.iPartitionNumber];
		}

	return KErrNone;
	}

void DBB5PartitionInfo::SessionEndCallBack(TAny* aSelf)
	{
	DBB5PartitionInfo& self = *static_cast<DBB5PartitionInfo*>(aSelf);
	self.DoSessionEndCallBack();
	}

void DBB5PartitionInfo::DoSessionEndCallBack()
	{
	iDriver->EndInCritical();

	TInt r = iSession->EpocErrorCode();

	if (r == KErrNone)
		r = DecodePartitionInfo();

	iDriver->PartitionInfoComplete(r == KErrNone ? r : KErrNotReady);
	}

TInt DBB5PartitionInfo::DecodePartitionInfo()
//
// decode partition info that was read into internal buffer
//
	{
	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">Mmc:PartitionInfo()"));
	TUint partitionCount = iPartitionInfo->iPartitionCount = 0;

	// For internal devices it is only valid to report up to 1 SWAP partition
	TBool foundSwap = EFalse;

	BGAHSMMCPTN_PI_STR *partitionTable = (BGAHSMMCPTN_PI_STR*)(&iIntBuf[0]);

	// Verify that this is the Nokia partition table
	if( memcompare( (TUint8*)&(partitionTable->id[0]), sizeof(BGAHSMMCPTN_PI_ID), (TUint8*)BGAHSMMCPTN_PI_ID, sizeof(BGAHSMMCPTN_PI_ID)) == 0 )
		{
		__KTRACE_OPT(KPBUSDRV, Kern::Printf("Nokia partition structure found"));
		__KTRACE_OPT(KPBUSDRV, Kern::Printf("partitionTable->id..............: %s", partitionTable->id ));
		__KTRACE_OPT(KPBUSDRV, Kern::Printf("partitionTable->sector_size.....: %d = 0x%x", partitionTable->sector_size, partitionTable->sector_size));
		__KTRACE_OPT(KPBUSDRV, Kern::Printf("partitionTable->major_ver.......: %d", partitionTable->major_ver));
		__KTRACE_OPT(KPBUSDRV, Kern::Printf("partitionTable->minor_ver.......: %d", partitionTable->minor_ver));
		__KTRACE_OPT(KPBUSDRV, Kern::Printf("partitionTable->partition_amount: %d", partitionTable->partition_amount));
		
		for( TUint8 index = 0; (index < partitionTable->partition_amount) && (index < BGAHSMMCPTN_LAST_DRIVE); index++ )
			{
			if( (partitionTable->partitions[index].size > 0) &&
				( PartitionIsFAT(partitionTable->partitions[index].partition_id) ||
				  PartitionIsFAT32(partitionTable->partitions[index].partition_id) ||
				  (KPartitionTypePagedData == partitionTable->partitions[index].partition_id && !foundSwap) ) )
				{
				iPartitionInfo->iEntry[partitionCount].iPartitionType	  = partitionTable->partitions[index].partition_id;
				iPartitionInfo->iEntry[partitionCount].iPartitionBaseAddr = (Int64) partitionTable->partitions[index].start_sector << KDiskSectorShift;
				iPartitionInfo->iEntry[partitionCount].iPartitionLen	  = (Int64) partitionTable->partitions[index].size << KDiskSectorShift;
				iPartitionAttributes[partitionCount]					  = partitionTable->partitions[index].partition_attributes;

				__KTRACE_OPT(KPBUSDRV, Kern::Printf("Registering partition #%d:", partitionCount));
				__KTRACE_OPT(KPBUSDRV, Kern::Printf("partitionCount....: %d", partitionCount));
				__KTRACE_OPT(KPBUSDRV, Kern::Printf("startSector.......: 0x%x", partitionTable->partitions[index].start_sector ));
				__KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionBaseAddr: 0x%lx (sectors: %d)", iPartitionInfo->iEntry[partitionCount].iPartitionBaseAddr, (TUint32)(iPartitionInfo->iEntry[partitionCount].iPartitionBaseAddr >> KDiskSectorShift)));
				__KTRACE_OPT(KPBUSDRV, Kern::Printf("size..............: 0x%lx", partitionTable->partitions[index].size ));
				__KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionLen.....: 0x%lx (sectors: %d)", iPartitionInfo->iEntry[partitionCount].iPartitionLen, iPartitionInfo->iEntry[partitionCount].iPartitionLen >> KDiskSectorShift));
				__KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionType....: %d", iPartitionInfo->iEntry[partitionCount].iPartitionType));
				__KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionAttribs.: 0x%x", iPartitionAttributes[partitionCount]));
				__KTRACE_OPT(KPBUSDRV, Kern::Printf(" "));

				if(KPartitionTypePagedData == partitionTable->partitions[index].partition_id)
					{
					foundSwap = ETrue;
					}

				partitionCount++;
				}
			}
		}

	// Validate partition address boundaries
	if(partitionCount == 0)
		{
		__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: No supported partitions found!"));
		return KErrCorrupt;
		}
	else
		{
		// at least one entry for a supported partition found
		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;
			}

		// Go through all partition entries and check boundaries
		for(TInt 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 - check #%d", i));
				return KErrCorrupt;
				}
			}
		}

	iPartitionInfo->iPartitionCount = partitionCount;
	iPartitionInfo->iMediaSizeInBytes = iCard->DeviceSize64();

	//Notify medmmc that partitioninfo is complete.
	iCallBack.CallBack();

	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<Mmc:PartitionInfo (C:%d)", partitionCount));
	return KErrNone;
	}


// End - DBB5PartitionInfo


EXPORT_C DEMMCPartitionInfo* CreateEmmcPartitionInfo()
	{
	return new DBB5PartitionInfo;
	}

DECLARE_STANDARD_EXTENSION()
	{
	return KErrNone;
	}

//	End of File