kernel/eka/drivers/medmmc/emmcptn.cpp
changeset 0 a41df078684a
child 33 0173bcd7697c
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Partition Management for Embedded MMC devices
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <drivers/emmcptn.h>
       
    19 
       
    20 const TInt KDiskSectorShift=9;
       
    21 
       
    22 class DLegacyEMMCPartitionInfo : public DEMMCPartitionInfo
       
    23 	{
       
    24 public:
       
    25 	 DLegacyEMMCPartitionInfo();
       
    26 	~DLegacyEMMCPartitionInfo();
       
    27 public:
       
    28 	virtual TInt Initialise(DMediaDriver* aDriver);
       
    29 	virtual TInt PartitionInfo(TPartitionInfo& anInfo, const TMMCCallBack& aCallBack);
       
    30 	virtual TInt PartitionCaps(TLocDrv& aDrive, TDes8& aInfo);
       
    31 	
       
    32 protected:
       
    33 	void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors);
       
    34 	
       
    35 private:
       
    36 	static void SessionEndCallBack(TAny* aSelf);
       
    37 		   void DoSessionEndCallBack();
       
    38 	virtual TInt DecodePartitionInfo();
       
    39 	
       
    40 protected:
       
    41 	DMediaDriver*   iDriver;
       
    42 	TPartitionInfo* iPartitionInfo;
       
    43 	TMMCCallBack	iSessionEndCallBack;
       
    44 	TMMCCallBack 	iCallBack;         // Where to report the PartitionInfo completion
       
    45 	DMMCSession*	iSession;
       
    46 	TMMCard*		iCard;
       
    47 	TUint8*			iIntBuf;
       
    48 	};
       
    49 
       
    50 DLegacyEMMCPartitionInfo::DLegacyEMMCPartitionInfo()
       
    51   : iSessionEndCallBack(DLegacyEMMCPartitionInfo::SessionEndCallBack, this)
       
    52 	{
       
    53 	}
       
    54 
       
    55 DLegacyEMMCPartitionInfo::~DLegacyEMMCPartitionInfo()
       
    56 	{
       
    57 	delete iSession;
       
    58 	}
       
    59 
       
    60 TInt DLegacyEMMCPartitionInfo::Initialise(DMediaDriver* aDriver)
       
    61 	{
       
    62 	iDriver = aDriver;
       
    63 
       
    64 	DMMCSocket* socket = ((DMMCSocket*)((DPBusPrimaryMedia*)(iDriver->iPrimaryMedia))->iSocket);
       
    65 	if(socket == NULL)
       
    66 		return(KErrNoMemory);
       
    67 
       
    68 	DMMCStack* stack = socket->Stack(0);
       
    69 	iCard = stack->CardP(((DPBusPrimaryMedia*)(iDriver->iPrimaryMedia))->iSlotNumber);
       
    70 	
       
    71 	iSession = stack->AllocSession(iSessionEndCallBack);
       
    72 	if (iSession == NULL)
       
    73 		return(KErrNoMemory);
       
    74 
       
    75 	iSession->SetStack(stack);
       
    76 	iSession->SetCard(iCard);
       
    77 
       
    78 	// this gets used before any access
       
    79 	TInt bufLen, minorBufLen;
       
    80 	stack->BufferInfo(iIntBuf, bufLen, minorBufLen);
       
    81 
       
    82 	return(KErrNone);
       
    83 	}
       
    84 
       
    85 TInt DLegacyEMMCPartitionInfo::PartitionInfo(TPartitionInfo& anInfo, const TMMCCallBack& aCallBack)
       
    86 	{
       
    87 	iPartitionInfo = &anInfo;
       
    88 	iCallBack = aCallBack;
       
    89 	// If media driver is persistent (see EMediaDriverPersistent), 
       
    90 	// the card may have changed since last power down, so reset CID
       
    91 	iSession->SetCard(iCard);
       
    92 	
       
    93 	iSession->SetupCIMReadBlock(0, iIntBuf);
       
    94 
       
    95 	TInt r = iDriver->InCritical();
       
    96 	if (r == KErrNone)
       
    97 		r = iSession->Engage();
       
    98 
       
    99 	if(r != KErrNone)
       
   100 		iDriver->EndInCritical();
       
   101 	
       
   102 	return(r);
       
   103 	}
       
   104 
       
   105 TInt DLegacyEMMCPartitionInfo::PartitionCaps(TLocDrv& aDrive, TDes8& aInfo)
       
   106 	{
       
   107 	 TLocalDriveCapsV6Buf& Info = static_cast< TLocalDriveCapsV6Buf&> (aInfo);
       
   108 	
       
   109 	// is this query for the swap partition ?
       
   110 	if (aDrive.iPartitionType == KPartitionTypePagedData)
       
   111 		{
       
   112 		Info().iFileSystemId = KDriveFileNone;
       
   113 		Info().iDriveAtt|= KDriveAttHidden;
       
   114 		}
       
   115 
       
   116 	// is this query for the ROFS partition ?
       
   117 	if (aDrive.iPartitionType == KPartitionTypeRofs)
       
   118 		{
       
   119 		Info().iFileSystemId = KDriveFileSysROFS;
       
   120 		Info().iMediaAtt&= ~KMediaAttFormattable;
       
   121 		Info().iMediaAtt|= KMediaAttWriteProtected;
       
   122 		}
       
   123 	
       
   124 	// is this query for the ROM partition ?
       
   125 	if (aDrive.iPartitionType == KPartitionTypeROM)
       
   126 		{
       
   127 		Info().iFileSystemId = KDriveFileNone;
       
   128 		Info().iMediaAtt&= ~KMediaAttFormattable;
       
   129 		Info().iMediaAtt|= KMediaAttWriteProtected;
       
   130 		}
       
   131 	
       
   132 	return KErrNone;
       
   133 	}
       
   134 
       
   135 void DLegacyEMMCPartitionInfo::SessionEndCallBack(TAny* aSelf)
       
   136 	{
       
   137 	DLegacyEMMCPartitionInfo& self = *static_cast<DLegacyEMMCPartitionInfo*>(aSelf);
       
   138 	self.DoSessionEndCallBack();
       
   139 	}
       
   140 
       
   141 void DLegacyEMMCPartitionInfo::DoSessionEndCallBack()
       
   142 	{
       
   143 	iDriver->EndInCritical();
       
   144 
       
   145 	TInt r = iSession->EpocErrorCode();
       
   146 
       
   147 	if (r == KErrNone)
       
   148 		r = DecodePartitionInfo();
       
   149 
       
   150 	iDriver->PartitionInfoComplete(r == KErrNone ? r : KErrNotReady);
       
   151 	}
       
   152 
       
   153 TInt DLegacyEMMCPartitionInfo::DecodePartitionInfo()
       
   154 //
       
   155 // decode partition info that was read into internal buffer 
       
   156 //
       
   157 	{
       
   158 	TUint partitionCount=iPartitionInfo->iPartitionCount=0;
       
   159 	TInt defaultPartitionNumber=-1;
       
   160 	TMBRPartitionEntry* pe;
       
   161 	const TUint KMBRFirstPartitionOffsetAligned = KMBRFirstPartitionOffset & ~3;
       
   162 	TInt i;
       
   163 
       
   164 	// Read of the first sector successful so check for a Master Boot Record
       
   165 	if (*(TUint16*)(&iIntBuf[KMBRSignatureOffset])!=0xAA55)
       
   166 		// If no valid signature give up now, No way to re-format an internal drive correctly
       
   167 		return KErrCorrupt;
       
   168 
       
   169 	__ASSERT_COMPILE(KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry) <= KMBRSignatureOffset);
       
   170 
       
   171 	memmove(&iIntBuf[0], &iIntBuf[2],
       
   172 		KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry)); 
       
   173 
       
   174 
       
   175 	for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]);
       
   176 		pe->iPartitionType != 0 && i < KMaxPartitionEntries; i++,pe--)
       
   177 		{
       
   178 		if (pe->IsDefaultBootPartition())
       
   179 			{
       
   180 			SetPartitionEntry(&iPartitionInfo->iEntry[0],pe->iFirstSector,pe->iNumSectors);
       
   181 			defaultPartitionNumber=i;
       
   182 			partitionCount++;
       
   183 			break;
       
   184 			}
       
   185 		}
       
   186 
       
   187 	// Now add any other partitions
       
   188 	for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]);
       
   189 		pe->iPartitionType != 0 && i < KMaxPartitionEntries; i++,pe--)
       
   190 		{
       
   191 		if (defaultPartitionNumber==i)
       
   192 			{
       
   193 			// Already sorted
       
   194 			}
       
   195 
       
   196 		// FAT partition ?
       
   197 		else if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition())
       
   198 			{
       
   199 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
       
   200 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: FAT partition found at sector #%u", pe->iFirstSector));
       
   201 			partitionCount++;
       
   202 			}
       
   203 
       
   204 		else if (pe->iPartitionType == KPartitionTypeROM)
       
   205 			{
       
   206 			TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount];
       
   207 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
       
   208 			partitionEntry.iPartitionType = pe->iPartitionType;
       
   209 			partitionCount++;				 
       
   210 
       
   211 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypeROM found at sector #%u", pe->iFirstSector));
       
   212 			}
       
   213 
       
   214 		// ROFS partition ?
       
   215 		else if (pe->iPartitionType == KPartitionTypeRofs)
       
   216 			{
       
   217 			
       
   218 // Don't expose this for normal operation only boot?			
       
   219 			TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount];
       
   220 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
       
   221 			partitionEntry.iPartitionType = pe->iPartitionType;
       
   222 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypeRofs found at sector #%u", pe->iFirstSector));
       
   223 			partitionCount++;
       
   224 			}
       
   225  
       
   226 		// Swap partition ?
       
   227 		else if (pe->iPartitionType == KPartitionTypePagedData)
       
   228 			{
       
   229 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypePagedData found at sector #%u", pe->iFirstSector));
       
   230 
       
   231 			TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount];
       
   232 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
       
   233 			partitionEntry.iPartitionType = pe->iPartitionType;
       
   234 			partitionCount++;
       
   235 			}
       
   236 		}
       
   237 
       
   238 	// Check the validity of the partition address boundaries
       
   239 	// If there is any MBR errors
       
   240 	if(partitionCount > 0)
       
   241 		{
       
   242 		const TInt64 deviceSize = iCard->DeviceSize64();
       
   243 		TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1];
       
   244 		// Check that the card address space boundary is not exceeded by the last partition
       
   245 		if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize)
       
   246 			{
       
   247 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space"));
       
   248 			return KErrCorrupt;
       
   249 			}
       
   250 		
       
   251 		// More than one partition. Go through all of them
       
   252 		if (partitionCount > 0)
       
   253 			{
       
   254 			for(i=partitionCount-1; i>0; i--)
       
   255 				{
       
   256 				const TPartitionEntry& curr = iPartitionInfo->iEntry[i];
       
   257 				TPartitionEntry& prev = iPartitionInfo->iEntry[i-1];
       
   258 				// Check if partitions overlap
       
   259 				if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen))
       
   260 					{
       
   261 					__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Overlapping partitions"));
       
   262 					return KErrCorrupt;
       
   263 					}
       
   264 				}
       
   265 			}
       
   266 		}
       
   267 
       
   268 	if (defaultPartitionNumber==(-1) && partitionCount==0)
       
   269 		{
       
   270 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("No Valid Partitions Found!"));
       
   271 		return KErrCorrupt;
       
   272 		}
       
   273 
       
   274 	iPartitionInfo->iPartitionCount=partitionCount;
       
   275 	iPartitionInfo->iMediaSizeInBytes=iCard->DeviceSize64();
       
   276 
       
   277 #ifdef _DEBUG
       
   278 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<Mmc:PartitionInfo (C:%d)",partitionCount));
       
   279 	for (TUint x=0; x<partitionCount; x++)
       
   280 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("     Partition%d (B:%xH L:%xH)",x,I64LOW(iPartitionInfo->iEntry[x].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[x].iPartitionLen)));
       
   281 #endif
       
   282 
       
   283 	//Notify medmmc that partitioninfo is complete.
       
   284 	iCallBack.CallBack();
       
   285 	
       
   286 	return(KErrNone);
       
   287 	}
       
   288 
       
   289 
       
   290 void DLegacyEMMCPartitionInfo::SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors)
       
   291 //
       
   292 // auxiliary static function to record partition information in TPartitionEntry object
       
   293 //
       
   294 	{
       
   295 	aEntry->iPartitionBaseAddr=aFirstSector;
       
   296 	aEntry->iPartitionBaseAddr<<=KDiskSectorShift;
       
   297 	aEntry->iPartitionLen=aNumSectors;
       
   298 	aEntry->iPartitionLen<<=KDiskSectorShift;
       
   299 	aEntry->iPartitionType=KPartitionTypeFAT12;
       
   300 	}
       
   301 
       
   302 // End - DLegacyEMMCPartitionInfo
       
   303 
       
   304 
       
   305 EXPORT_C DEMMCPartitionInfo* CreateEmmcPartitionInfo()
       
   306 	{
       
   307 	return new DLegacyEMMCPartitionInfo;
       
   308 	}
       
   309 
       
   310 DECLARE_STANDARD_EXTENSION()
       
   311 	{
       
   312 	return KErrNone;
       
   313 	}