os/kernelhwsrv/kernel/eka/drivers/pbus/mmc/stack.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1999-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 // \e32\drivers\pbus\mmc\stack.cpp
    15 // 
    16 //
    17 
    18 #include <drivers/mmc.h>
    19 #include <kernel/kern_priv.h>
    20 #include <drivers/locmedia.h>
    21 #include "stackbody.h"
    22 
    23 #include "OstTraceDefinitions.h"
    24 #ifdef OST_TRACE_COMPILER_IN_USE
    25 #include "locmedia_ost.h"
    26 #ifdef __VC32__
    27 #pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
    28 #endif
    29 #include "stackTraces.h"
    30 #endif
    31 
    32 #ifdef __SMP__
    33 TSpinLock MMCLock(TSpinLock::EOrderGenericIrqHigh0);
    34 #endif
    35 
    36 #define ASSERT_NOT_ISR_CONTEXT	__ASSERT_DEBUG(NKern::CurrentContext()!=NKern::EInterrupt,DMMCSocket::Panic(DMMCSocket::EMMCUnblockingInWrongContext));
    37 
    38 #if !defined(__WINS__)
    39 #define DISABLEPREEMPTION TUint irq = __SPIN_LOCK_IRQSAVE(MMCLock);
    40 #define RESTOREPREEMPTION __SPIN_UNLOCK_IRQRESTORE(MMCLock,irq);
    41 #else
    42 #define DISABLEPREEMPTION
    43 #define RESTOREPREEMPTION										   
    44 #endif
    45 
    46 //#define ENABLE_DETAILED_SD_COMMAND_TRACE
    47 
    48 // default length of minor buffer - must have at least enough space for one sector
    49 const TInt KMinMinorBufSize = 512;
    50 
    51 //	MultiMedia Card Controller - Generic level code for controller, intermediate
    52 //	level code for media change and power supply handling
    53 
    54 EXPORT_C TUint TCSD::CSDField(const TUint& aTopBit, const TUint& aBottomBit) const
    55 /**
    56  * Extract bitfield from CSD
    57  */
    58 	{
    59 	const TUint indexT=KMMCCSDLength-1-aTopBit/8;
    60 	const TUint indexB=KMMCCSDLength-1-aBottomBit/8;
    61 	return(((indexT==indexB ? iData[indexT]
    62 			: (indexT+1)==indexB ? ((iData[indexT]<<8) | iData[indexT+1])
    63 			: ((iData[indexT]<<16) | (iData[indexT+1]<<8) | iData[indexT+2])
    64 			) >> (aBottomBit&7)) & ((1<<(aTopBit-aBottomBit+1))-1));
    65 	}
    66 
    67 
    68 //	--------  class TCSD  --------
    69 // Raw field accessor functions are defined in mmc.inl.  These functions return
    70 // values that require extra computation, such as memory capacity.
    71 
    72 
    73 EXPORT_C TUint TCSD::DeviceSize() const
    74 /**
    75  *
    76  * Calculate device capacity from CSD
    77  * 
    78  * Section 5.3, MMCA Spec 2.2 (Jan 2000)
    79  *
    80  * memory capacity = BLOCKNR * BLOCK_LEN
    81  * where
    82  *	BLOCKNR = (C_SIZE + 1) * MULT; MULT = 2 ** (C_MULT_SIZE + 2);
    83  *	BLOCK_LEN = 2 ** (READ_BL_LEN)
    84  *
    85  * memory capacity	= (C_SIZE + 1) * (2 ** (C_MULT_SIZE + 2)) * (2 ** READ_BL_LEN)
    86  *					= (C_SIZE + 1) * (2 ** (C_MULT_SIZE + 2 + READ_BL_LEN))
    87  *
    88  * @return Device Capacity
    89  */
    90 	{
    91 	__KTRACE_OPT(KPBUS1, Kern::Printf("csd:ds:0x%x,0x%x,0x%x", ReadBlLen(), CSize(), CSizeMult()));
    92 
    93 	const TUint blockLog = ReadBlLen();
    94 	if( blockLog > 11 )
    95 		return( 0 );
    96 
    97 	const TUint size = (CSize() + 1) << (2 + CSizeMult() + blockLog);
    98 
    99 	if( size == 0 )
   100 		return( 0xFFF00000 );
   101 
   102 	return( size );
   103 	}
   104 
   105 EXPORT_C TMMCMediaTypeEnum TCSD::MediaType() const
   106 /**
   107  * This function makes a rough approximation if media type based on supported
   108  * command classes (CCC).
   109  *
   110  * @return TMMCMediaTypeEnum describing the type of media.
   111  */
   112 	{
   113 	struct mediaTableEntry
   114 		{
   115 		TUint iMask;
   116 		TUint iValue;
   117 		TMMCMediaTypeEnum iMedia;
   118 		};
   119 
   120 	const TUint testMask = (KMMCCmdClassBlockRead|KMMCCmdClassBlockWrite|KMMCCmdClassErase|KMMCCmdClassIOMode);
   121 	static const mediaTableEntry mediaTable[] = 
   122 		{
   123 		{KMMCCmdClassBasic, 0,																  EMultiMediaNotSupported},
   124 		{testMask,			(KMMCCmdClassBlockRead|KMMCCmdClassBlockWrite|KMMCCmdClassErase), EMultiMediaFlash},
   125 		{testMask,			KMMCCmdClassBlockRead|KMMCCmdClassBlockWrite,					  EMultiMediaFlash},
   126 		{testMask,			KMMCCmdClassBlockRead|KMMCCmdClassErase,						  EMultiMediaROM},
   127 		{testMask,			KMMCCmdClassBlockRead,											  EMultiMediaROM},
   128 		{KMMCCmdClassIOMode,KMMCCmdClassIOMode,												  EMultiMediaIO},
   129 		{0,					0,																  EMultiMediaOther}
   130 		};
   131 
   132 	const TUint ccc = CCC();
   133 	const mediaTableEntry* ptr = mediaTable;
   134 
   135 	while( (ccc & ptr->iMask) != (ptr->iValue) )
   136 		ptr++;
   137 
   138     if (ptr->iMedia == EMultiMediaFlash)
   139         {
   140         // Further check PERM_WRITE_PROTECT and TMP_WRITE_PROTECT bits
   141         if (PermWriteProtect() || TmpWriteProtect())
   142             return EMultiMediaROM;
   143         }
   144 
   145 	return( ptr->iMedia );
   146 	}
   147 
   148 EXPORT_C TUint TCSD::ReadBlockLength() const
   149 /**
   150  * Calculates the read block length from the CSD.
   151  * READ_BL_LEN is encoded as a logarithm.
   152  *
   153  * @return The read block length 
   154  */
   155 	{
   156 	const TUint blockLog = ReadBlLen();
   157 	
   158 	//SD version 2.0 or less the range is 0-11
   159 	//MMC version 4.1 or less the range is 0-11
   160 	//MMC version 4.2 the range is 0-14 (15 is reserved for future use)
   161 	//But we cannot differentiate among 4.x
   162 	//Hence , 0-14 is supported for 4.x
   163 	if (SpecVers() < 4)
   164 		{
   165 		if( blockLog > 11 )
   166 			return( 0 );
   167 		}
   168 	else
   169 		{
   170 		if(blockLog > 14)
   171 			return ( 0 );
   172 		}
   173 
   174 	return( 1 << blockLog );
   175 	}
   176 
   177 EXPORT_C TUint TCSD::WriteBlockLength() const
   178 /**
   179  * Calculates the write block length from the CSD.
   180  * WRITE_BL_LEN is encoded as a logarithm.
   181  *
   182  * @return The write block length 
   183  */
   184 	{
   185 	const TUint blockLog = WriteBlLen();
   186 	if( blockLog > 11 )
   187 		return( 0 );
   188 
   189 	return( 1 << blockLog );
   190 	}
   191 
   192 EXPORT_C TUint TCSD::EraseSectorSize() const
   193 /**
   194  * Calculates the erase sector size from the CSD.
   195  * SECTOR_SIZE is a 5 bit value, which is one less than the number of write
   196  *
   197  * @return The erase sector size
   198  */
   199 	{
   200 	if (SpecVers() < 3)
   201 		{
   202 		// V2.2 and earlier supports erase sectors. Read sector size from CSD(46:42) - confusingly now reassigned as
   203 		// erase group size. 
   204 		return( (EraseGrpSize()+1) * WriteBlockLength() );
   205 		}
   206 	else
   207 		{
   208 		// Support for erase sectors removed from V3.1 onwards
   209 		return(0);	
   210 		}
   211 
   212 	}
   213 
   214 EXPORT_C TUint TCSD::EraseGroupSize() const
   215 /**
   216  * Calculates the erase group size from the CSD.
   217  * ERASE_GRP_SIZE is a 5 bit value, which is one less than the number of erase
   218  * sectors in an erase group.
   219  *
   220  * @return The erase group size
   221  */
   222 	{
   223 	if (SpecVers() < 3)
   224 		{
   225 		// For V2.2 and earlier, the erase group size is held in CSD(41:37)  - confusingly now reassigned as the erase
   226 		// group multiplier. The units for this are erase sectors, so need to convert to write blocks and then bytes.
   227 		TUint erSecSizeInBytes=(EraseGrpSize()+1) * WriteBlockLength();
   228 		return( (EraseGrpMult()+1) * erSecSizeInBytes );
   229 		}
   230 	else
   231 		{
   232 		// For V3.1 onwards, the erase group size is determined by multiplying the erase group size - CSD(41:37) by the
   233 		// erase group multiplier - CSD(46:42)). The units for this are write blocks, so need to convert to bytes.  
   234 		TUint erGrpSizeInWrBlk = (EraseGrpSize()+1) * (EraseGrpMult()+1);
   235 		return(erGrpSizeInWrBlk * WriteBlockLength());
   236 		}	
   237 	}
   238 
   239 EXPORT_C TUint TCSD::MinReadCurrentInMilliamps() const
   240 /**
   241  * Calculates the minimum read current from the CSD.
   242  * VDD_R_CURR_MIN is a three bit value which is mapped to a number of mA.
   243  * 0 actually maps to 0.5mA, but has been rounded up.
   244  *
   245  * @return The minimum read current, in Milliamps
   246  */
   247 	{
   248 	static const TUint8 minConsumptionTable[] = {1,1,5,10,25,35,60,100};
   249 	return( minConsumptionTable[VDDRCurrMin()] );
   250 	}
   251 
   252 EXPORT_C TUint TCSD::MinWriteCurrentInMilliamps() const
   253 /**
   254  * Calculates the minimum write current from the CSD.
   255  * VDD_W_CURR_MIN is a three bit value which is mapped to a number of mA.
   256  *
   257  * @return The minimum write current, in Milliamps
   258  */
   259 	{
   260 	static const TUint8 minConsumptionTable[] = {1,1,5,10,25,35,60,100};
   261 	return( minConsumptionTable[VDDWCurrMin()] );
   262 	}
   263 
   264 EXPORT_C TUint TCSD::MaxReadCurrentInMilliamps() const
   265 /**
   266  * Calculates the maximum read current from the CSD.
   267  * VDD_R_CURR_MAX is a three bit value which is mapped to a number of mA.
   268  * 0 actually maps to 0.5mA, but has been rounded up.
   269  *
   270  * @return The maximum read current, in Milliamps
   271  */
   272 	{
   273 	static const TUint8 maxConsumptionTable[] = {1,5,10,25,35,45,80,200};
   274 	return( maxConsumptionTable[VDDRCurrMax()] );
   275 	}
   276 
   277 EXPORT_C TUint TCSD::MaxWriteCurrentInMilliamps() const
   278 /**
   279  * Calculates the maximum write current from the CSD.
   280  * VDD_W_CURR_MAX is a three bit value which is mapped to a number of mA.
   281  *
   282  * @return The maximum write current, in Milliamps
   283  */
   284 	{
   285 	static const TUint8 maxConsumptionTable[] = {1,5,10,25,35,45,80,200};
   286 	return( maxConsumptionTable[VDDWCurrMax()] );
   287 	}
   288 
   289 EXPORT_C TUint TCSD::MaxTranSpeedInKilohertz() const
   290 /**
   291  * TRAN_SPEED is an eight bit value which encodes three fields.
   292  * Section 5.3, MMCA Spec 2.2 (Jan 2000)
   293  *
   294  *	2:0	transfer rate unit	values 4 to 7 are reserved.
   295  *	6:3	time value
   296  *
   297  * @return Speed, in Kilohertz
   298  */
   299 	{
   300 	// tranRateUnits entries are all divided by ten so tranRateValues can be integers
   301 	static const TUint tranRateUnits[8] = {10,100,1000,10000,10,10,10,10};
   302 	static const TUint8 tranRateValues[16] = {10,10,12,13,15,20,25,30,35,40,45,50,55,60,70,80};
   303 	const TUint ts = TranSpeed();
   304 	return( tranRateUnits[ts&7] * tranRateValues[(ts>>3)&0xF] );
   305 	}
   306 
   307 //	--------  class TMMCard  --------
   308 
   309 TMMCard::TMMCard()
   310 : iIndex(0), iUsingSessionP(0), iFlags(0), iBusWidth(1)
   311 	{
   312 	// empty.
   313 	}
   314 
   315 EXPORT_C TBool TMMCard::IsReady() const
   316 /**
   317  * Predicate for if card is mounted and in standby/transfer/sleep state.
   318  *
   319  * @return ETrue if ready, EFalse otherwise.
   320  */
   321 	{
   322 	const TUint state = iStatus.State();
   323 	__KTRACE_OPT(KPBUS1, Kern::Printf("=mcc:ir:%d,0x%08x", IsPresent(), state));
   324 	OstTraceExt2( TRACE_INTERNALS, TMMCARD_ISREADY, "IsPresent=%d; state=0x%08x", IsPresent(), state );
   325 	
   326 	return IsPresent() && (state == ECardStateStby || state == ECardStateTran || state == ECardStateSlp);
   327 	}
   328 
   329 EXPORT_C TBool TMMCard::IsLocked() const
   330 /**
   331  * Predicate for if card is locked
   332  * 
   333  * It would be useful to check if the CSD supports the password protection
   334  * feature.  Password protection was introduced in c3.1, 05/99 and SPEC_VERS
   335  * is encoded 0 |-> 1.0 - 1.2, 1 |-> 1.4, 3 |-> 2.2.  Some cards support
   336  * password locking but their CSD reports SPEC_VERS == 1.
   337  *
   338  * @return ETrue if locked, EFalse otherwise.
   339  */
   340 	{
   341 	OstTraceFunctionEntry1( TMMCARD_ISLOCKED_ENTRY, this );
   342 	if ( !IsPresent() ) 
   343 		return( EFalse );
   344 
   345 	return( (TUint32(iStatus) & KMMCStatCardIsLocked) != 0 );
   346 	}
   347 
   348 TInt64 TMMCard::DeviceSize64() const
   349 /**
   350  * Returns the size of the MMC card in bytes
   351  * @return The size of the MMC card in bytes.
   352  */
   353 	{
   354 	OstTraceFunctionEntry1( TMMCARD_DEVICESIZE64_ENTRY, this );
   355 	const TBool highCapacity = IsHighCapacity();
   356 	const TUint32 sectorCount = ExtendedCSD().SectorCount();
   357 	
   358 	return ((highCapacity && sectorCount) ? (((TInt64)ExtendedCSD().SectorCount()) * 512) : (TInt64)CSD().DeviceSize());
   359 	}
   360 
   361 TUint32 TMMCard::PreferredWriteGroupLength() const
   362 /**
   363  * Returns the write group length.  Provided by the variant.
   364  * Default implementation returns a multiple of the write block length, as indicated by the CSD.
   365  * @return The preferred write group length.
   366  */
   367 	{
   368 	OstTraceFunctionEntry1( TMMCARD_PREFERREDWRITEGROUPLENGTH_ENTRY, this );
   369 	return(CSD().WriteBlockLength() << 5);	// 16K for a standard 512byte block length
   370 	}
   371 
   372 TInt TMMCard::GetFormatInfo(TLDFormatInfo& /*aFormatInfo*/) const
   373 /**
   374  * Returns the preferred format parametersm for the partition.
   375  * Implemented at the Variant layer.
   376  * @return Standard Symbian OS error code.
   377  */
   378 	{
   379 	return KErrNotSupported;
   380 	}
   381 
   382 TUint32 TMMCard::MinEraseSectorSize() const
   383 /**
   384  * Returns the minimum erase sector size.  Provided by the variant.
   385  * Default implementation returns the erase sector size, as indicated by the CSD.
   386  * @return The minimum erase sector size.
   387  */
   388 	{
   389 	return CSD().EraseSectorSize();
   390 	}
   391 
   392 TUint32 TMMCard::EraseSectorSize() const
   393 /**
   394  * Returns the recommended erase sector size.  Provided by the variant.
   395  * Default implementation returns the erase sector size, as indicated by the CSD.
   396  * @return The recommended erase sector size.
   397  */
   398 	{
   399 	return CSD().EraseSectorSize();
   400 	}
   401 
   402 LOCAL_C TBool IsPowerOfTwo(TInt aNum)
   403 //
   404 // Returns ETrue if aNum is a power of two
   405 //
   406 	{
   407 	return (aNum != 0 && (aNum & -aNum) == aNum);
   408 	}
   409 	
   410 TInt TMMCard::GetEraseInfo(TMMCEraseInfo& aEraseInfo) const
   411 /**
   412  * Return info. on erase services for this card
   413  * @param aEraseInfo A reference to the TMMCEraseInfo to be filled in with the erase information.
   414  * @return Symbian OS error code.
   415  */
   416 	{
   417 	OstTraceFunctionEntry1( TMMCARD_GETERASEINFO_ENTRY, this );
   418 	
   419 	// Check whether this card supports Erase Class Commands. Also, validate the erase group size
   420 	if ((CSD().CCC() & KMMCCmdClassErase) && IsPowerOfTwo(CSD().EraseGroupSize()))
   421 		{
   422 		// This card supports erase cmds. Also, all versions of MMC cards support Erase Group commands (i.e. CMD35, CMD36).
   423 		OstTrace0( TRACE_INTERNALS, TMMCARD_GETERASEINFO, "Card supports erase class commands" );
   424 		aEraseInfo.iEraseFlags=(KMMCEraseClassCmdsSupported|KMMCEraseGroupCmdsSupported); 
   425 		
   426 		// Return the preferred size to be used as the unit for format operations. We need to return a sensible
   427 		// multiple of the erase group size - as calculated by the CSD. A value around 1/32th of the total disk
   428 		// size generally results in an appropriate number of individual format calls.
   429 		const TInt64 devSizeDividedBy32=(DeviceSize64()>>5);
   430 		aEraseInfo.iPreferredEraseUnitSize=CSD().EraseGroupSize();
   431 		while (aEraseInfo.iPreferredEraseUnitSize < devSizeDividedBy32)
   432 			aEraseInfo.iPreferredEraseUnitSize<<=1;
   433 	
   434 		// Return the smallest size that can be used as the unit for erase operations. For erase group commands, this
   435 		// is the erase group size. 
   436 		aEraseInfo.iMinEraseSectorSize=CSD().EraseGroupSize();
   437 		} 
   438 	else	
   439 		aEraseInfo.iEraseFlags=0;
   440 	
   441 	OstTraceFunctionExitExt( TMMCARD_GETERASEINFO_EXIT, this, KErrNone );
   442 	return KErrNone;
   443 	}
   444 
   445 TUint TMMCard::MaxTranSpeedInKilohertz() const
   446 /**
   447  * Returns the maximum supported clock rate for the card, in Kilohertz.
   448  * @return Speed, in Kilohertz
   449  */
   450 	{
   451 	OstTraceFunctionEntry1( TMMCARD_MAXTRANSPEEDINKILOHERTZ_ENTRY, this );
   452 	// Default implementation obtains the transaction speed from the CSD
   453 	TUint32 highSpeedClock = HighSpeedClock();
   454 	return(highSpeedClock ? highSpeedClock : iCSD.MaxTranSpeedInKilohertz());
   455 	}
   456 
   457 
   458 TInt TMMCard::MaxReadBlLen() const
   459 /**
   460  * Returns the maximum read block length supported by the card encoded as a logarithm
   461  * Normally this is the same as the READ_BL_LEN field in the CSD register,
   462  * but for high capacity cards (>- 2GB) this is set to a maximum of 512 bytes,
   463  * if possible, to try to avoid compatibility issues.
   464  */
   465 	{
   466 	OstTraceFunctionEntry1( TMMCARD_MAXREADBLLEN_ENTRY, this );
   467 	const TInt KDefaultReadBlockLen = 9;	// 2^9 = 512 bytes
   468 	const TCSD& csd = CSD();
   469 
   470 	TInt blkLenLog2 = csd.ReadBlLen();
   471 
   472 	if (blkLenLog2 > KDefaultReadBlockLen)
   473 		{
   474 		__KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl %d", blkLenLog2));
   475 		OstTrace1( TRACE_INTERNALS, TMMCARD_MAXREADBLLEN1, "Block length 1=%d", blkLenLog2 );
   476 		
   477 		
   478 		if (csd.ReadBlPartial() || CSD().SpecVers() >= 4)
   479 			{
   480 			//
   481 			// MMC System Spec 4.2 states that 512 bytes blocks are always supported, 
   482 			// regardless of the state of READ_BL_PARTIAL 
   483 			//
   484 			blkLenLog2 = KDefaultReadBlockLen;	
   485 			__KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl -> %d", blkLenLog2));
   486 			OstTrace1( TRACE_INTERNALS, TMMCARD_MAXREADBLLEN2, "Block length 2=%d", blkLenLog2 );
   487 			}
   488 		}
   489 
   490 	OstTraceFunctionExitExt( TMMCARD_MAXREADBLLEN_EXIT, this, blkLenLog2 );
   491 	return blkLenLog2;
   492 
   493 	}
   494 
   495 TInt TMMCard::MaxWriteBlLen() const
   496 /**
   497  * Returns the maximum write block length supported by the card encoded as a logarithm
   498  * Normally this is the same as the WRITE_BL_LEN field in the CSD register,
   499  * but for high capacity cards (>- 2GB) this is set to a maximum of 512 bytes,
   500  * if possible, to try to avoid compatibility issues.
   501  */
   502 	{
   503 	OstTraceFunctionEntry1( TMMCARD_MAXWRITEBLLEN_ENTRY, this );
   504 	const TInt KDefaultWriteBlockLen = 9;	// 2^9 = 512 bytes
   505 	const TCSD& csd = CSD();
   506 
   507 	TInt blkLenLog2 = csd.WriteBlLen();
   508 
   509 	if (blkLenLog2 > KDefaultWriteBlockLen)
   510 		{
   511 		__KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl %d", blkLenLog2));
   512 		OstTrace1( TRACE_INTERNALS, TMMCARD_MAXWRITEBLLEN1, "Block length 1=%d", blkLenLog2 );
   513 		if (csd.WriteBlPartial() || CSD().SpecVers() >= 4)
   514 			{
   515 			//
   516 			// MMC System Spec 4.2 states that 512 bytes blocks are always supported, 
   517 			// regardless of the state of READ_BL_PARTIAL 
   518 			//
   519 			blkLenLog2 = KDefaultWriteBlockLen;	
   520 			__KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl -> %d", blkLenLog2));
   521 			OstTrace1( TRACE_INTERNALS, TMMCARD_MAXWRITEBLLEN2, "Block length 1=%d", blkLenLog2 );
   522 			}
   523 		}
   524 
   525 	OstTraceFunctionExitExt( TMMCARD_MAXWRITEBLLEN_EXIT, this, blkLenLog2 );
   526 	return blkLenLog2;
   527 
   528 	}
   529 
   530 //	--------  class TMMCardArray  --------
   531 
   532 EXPORT_C TInt TMMCardArray::AllocCards()
   533 /** 
   534  * Allocate TMMCard objects for iCards and iNewCardsArray.
   535  * This function is called at bootup as part of stack allocation so there
   536  * is no cleanup if it fails.
   537  *
   538  * @return KErrNone if successful, Standard Symbian OS error code otherwise.
   539  */
   540 	{
   541 	OstTraceFunctionEntry1( TMMCARDARRAY_ALLOCCARDS_ENTRY, this );
   542 	for (TUint i = 0; i < KMaxMMCardsPerStack; ++i)
   543 		{
   544 		// zeroing the card data used to be implicit because embedded in
   545 		// CBase-derived DMMCStack.
   546 		if ((iCards[i] = new TMMCard) == 0)
   547 		    {
   548 			OstTraceFunctionExitExt( TMMCARDARRAY_ALLOCCARDS_EXIT1, this, KErrNoMemory );
   549 			return KErrNoMemory;
   550 		    }
   551 		iCards[i]->iUsingSessionP = 0;
   552 		if ((iNewCards[i] = new TMMCard) == 0)
   553 		    {
   554 			OstTraceFunctionExitExt( TMMCARDARRAY_ALLOCCARDS_EXIT2, this, KErrNoMemory );
   555 			return KErrNoMemory;
   556 		    }
   557 		iNewCards[i]->iUsingSessionP = 0;
   558 		}
   559 
   560 	OstTraceFunctionExitExt( TMMCARDARRAY_ALLOCCARDS_EXIT3, this, KErrNone );
   561 	return KErrNone;
   562 	}
   563 
   564 void TMMCardArray::InitNewCardScan()
   565 /**
   566  * Prepare card array for new scan.
   567  */
   568 	{
   569 	OstTraceFunctionEntry1( TMMCARDARRAY_INITNEWCARDSCAN_ENTRY, this );
   570 	iNewCardsCount=0;
   571 	OstTraceFunctionExit1( TMMCARDARRAY_INITNEWCARDSCAN_EXIT, this );
   572 	}
   573 
   574 void TMMCardArray::MoveCardAndLockRCA(TMMCard& aSrcCard,TMMCard& aDestCard,TInt aDestIndex)
   575 /**
   576  * Copy card object and lock RCA.
   577  */
   578 	{
   579 	OstTraceExt2(TRACE_FLOW, TMMCARDARRAY_MOVECARDANDLOCKRCA_ENTRY, "TMMCardArray::MoveCardAndLockRCA;aDestIndex=%d;this=%x", aDestIndex, (TUint) this);
   580 	__KTRACE_OPT(KPBUS1, Kern::Printf("=mca:mclr:%d", aDestIndex));
   581 
   582 	aDestCard.iCID=aSrcCard.iCID;
   583 	aDestCard.iRCA=aSrcCard.iRCA;
   584 	aDestCard.iCSD=aSrcCard.iCSD;
   585 	aDestCard.iIndex=aDestIndex;		// Mark card as being present
   586 	aDestCard.iFlags=aSrcCard.iFlags;
   587 	aDestCard.iBusWidth=aSrcCard.iBusWidth;
   588 	aDestCard.iHighSpeedClock = aSrcCard.iHighSpeedClock;
   589 
   590 	iOwningStack->iRCAPool.LockRCA(aDestCard.iRCA);
   591 
   592 	// Now that we have transferred ownership, reset the source card
   593 	aSrcCard.iRCA = aSrcCard.iIndex = aSrcCard.iFlags = 0;
   594 	aSrcCard.iBusWidth = 1;
   595 	aSrcCard.iHighSpeedClock = 0;
   596 
   597 	aSrcCard.iUsingSessionP = NULL;
   598 	OstTraceFunctionExit1( TMMCARDARRAY_MOVECARDANDLOCKRCA_EXIT, this );
   599 	}
   600 
   601 EXPORT_C void TMMCardArray::AddNewCard(const TUint8* aCID,TRCA* aNewRCA)
   602 /**
   603  * Found a new card to add to the array. Add it to a separate array for now
   604  * since we need to know all the cards present before we start replacing old
   605  * entries.
   606  */
   607 	{
   608 	OstTraceFunctionEntryExt( TMMCARDARRAY_ADDNEWCARD_ENTRY, this );
   609 	// Store the CID in the next free slot
   610 	NewCard(iNewCardsCount).iCID = aCID;
   611 
   612 	*aNewRCA=0;
   613 
   614 	// Now let's look if we've seen this card before
   615 	for ( TUint i=0 ; i<iOwningStack->iMaxCardsInStack ; i++ )
   616 		{
   617 		if ( Card(i).iCID==NewCard(iNewCardsCount).iCID )
   618 			{
   619 			*aNewRCA=Card(i).iRCA;
   620 			NewCard(iNewCardsCount).iIndex=(i+1);
   621 			break;
   622 			}
   623 		}
   624 
   625 	if ( *aNewRCA==0 )
   626 		{
   627 		// Not seen this one before so get a new RCA for the card
   628 		NewCard(iNewCardsCount).iIndex=0;
   629 		__ASSERT_ALWAYS( (*aNewRCA=iOwningStack->iRCAPool.GetFreeRCA())!=0,DMMCSocket::Panic(DMMCSocket::EMMCNoFreeRCA) );
   630 		}
   631 
   632 	__KTRACE_OPT(KPBUS1, Kern::Printf("mca:adn: assigning new card %d rca 0x%04x", iNewCardsCount, TUint16(*aNewRCA) ));
   633 	OstTraceExt2( TRACE_INTERNALS, TMMCARDARRAY_ADDNEWCARD, "iNewCardsCount=%d; RCA=0x%04x", iNewCardsCount, (TUint) *aNewRCA );
   634 	
   635 	NewCard(iNewCardsCount).iRCA=*aNewRCA;
   636 	iNewCardsCount++;
   637 	OstTraceFunctionExit1( TMMCARDARRAY_ADDNEWCARD_EXIT, this );
   638 	}
   639 
   640 TInt TMMCardArray::MergeCards(TBool aFirstPass)
   641 /**
   642  * This function places newly acquired cards from the new card array into free
   643  * slots of the main card array.
   644  * Returns KErrNotFound if not able to successfully place all the new cards.
   645  */
   646 	{
   647 	OstTraceFunctionEntryExt( TMMCARDARRAY_MERGECARDS_ENTRY, this );
   648 
   649 	
   650 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mca:mc:%d,%d", aFirstPass, iNewCardsCount));
   651 	OstTrace1( TRACE_INTERNALS, TMMCARDARRAY_MERGECARDS1, "iNewCardsCount=%d", iNewCardsCount );
   652 	
   653 	TUint i;	// New card index
   654 	TUint j;	// Main card index
   655 
   656 	// Only do this on first pass. Setup any new cards which were already there
   657 	if (aFirstPass)
   658 		{
   659 		for ( i=0 ; i<iNewCardsCount ; i++ )
   660 			{
   661 			__KTRACE_OPT(KPBUS1, Kern::Printf("-mca:fp,i=%d,idx=0x%x", i, NewCard(i).iIndex));
   662 			OstTraceExt2( TRACE_INTERNALS, TMMCARDARRAY_MERGECARDS2, "i=%d; Index=0x%x", i, NewCard(i).iIndex );
   663 			if( NewCard(i).iIndex != 0 ) // Signifies card was here before (iIndex has old slot number +1)
   664 				{
   665 				// Put it in the same slot as before
   666 				j=(NewCard(i).iIndex-1);
   667 				MoveCardAndLockRCA(NewCard(i),Card(j),(j+1));
   668 				}
   669 			}
   670 		}
   671 
   672 	for ( i=0,j=0 ; i<iNewCardsCount ; i++ )
   673 		{
   674 		__KTRACE_OPT(KPBUS1, Kern::Printf("-mca:i=%d,j=%d,rca=0x%4x", i, j, TUint16(NewCard(i).iRCA) ));
   675 		if ( NewCard(i).iRCA != 0 )
   676 			{
   677 			// Find a spare slot in main array for this new card
   678 			while ( Card(j).IsPresent() )
   679 				if ( ++j==iOwningStack->iMaxCardsInStack )
   680 				    {
   681 					OstTraceFunctionExitExt( TMMCARDARRAY_MERGECARDS_EXIT1, this, KErrNotFound );
   682 					return KErrNotFound;
   683 				    }
   684 
   685 			// Found a free slot; move the card info there
   686 			__KTRACE_OPT(KPBUS1, Kern::Printf("-mca:freej=%d,rca=0x%04x", j, TUint16(Card(j).iRCA) ));
   687 			OstTraceExt2( TRACE_INTERNALS, TMMCARDARRAY_MERGECARDS3, "j=%d; RCA=0x%04x", j, (TUint) (Card(j).iRCA) );
   688 			if ( Card(j).iRCA != 0 )
   689 				iOwningStack->iRCAPool.UnlockRCA(Card(j).iRCA);
   690 
   691 			__KTRACE_OPT(KPBUS1, Kern::Printf("merging new card %d to card %d dest index %d", i, j, j+1));
   692 			OstTraceExt3( TRACE_INTERNALS, TMMCARDARRAY_MERGECARDS4, "Merging new card %d to card %d; Destination index=%d", (TInt) i, (TInt) j, (TInt) j+1 );
   693 			MoveCardAndLockRCA(NewCard(i),Card(j),(j+1));
   694 			}
   695 		}
   696 	OstTraceFunctionExitExt( TMMCARDARRAY_MERGECARDS_EXIT2, this, KErrNone );
   697 	return KErrNone;
   698 	}
   699 
   700 void TMMCardArray::UpdateAcquisitions(TUint* aMaxClock)
   701 /**
   702  * Called when we have successfully stored a new set of cards in the card array.
   703  * This performs final initialisation of the card entries and determines the
   704  * maximum bus clock that can be employed - by checking the CSD of each card.
   705  */
   706 	{
   707 	OstTraceFunctionEntryExt( TMMCARDARRAY_UPDATEACQUISITIONS_ENTRY, this );
   708 	
   709 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mca:uda"));
   710 	iCardsPresent=0;
   711 	TUint maxClk = iOwningStack->iMultiplexedBus ? 1 : 800000; // ???
   712 	for ( TUint i=0 ; i < (iOwningStack->iMaxCardsInStack) ; i++ )
   713 		{
   714 		if ( Card(i).IsPresent() )
   715 			{
   716 			// General initialisation
   717 			iCardsPresent++;
   718 			Card(i).iSetBlockLen=0;
   719 			Card(i).iLastCommand=ECmdSendStatus;
   720 
   721 			// Check each card present to determine appropriate bus clock
   722 			TUint maxTS = iOwningStack->MaxTranSpeedInKilohertz(Card(i));
   723 			if(iOwningStack->iMultiplexedBus)
   724 				{
   725 				if ( maxTS > maxClk )
   726 					maxClk = maxTS;
   727 				}
   728 			else
   729 				{
   730 				if ( maxTS < maxClk )
   731 					maxClk = maxTS;
   732 				}
   733 			}
   734 		}
   735 	// ??? Should also calculate here and return the data timeout and busy timeout 
   736 	// instead of relying on ASSP defaults.
   737 
   738 	*aMaxClock=maxClk;
   739 	OstTraceFunctionExit1( TMMCARDARRAY_UPDATEACQUISITIONS_EXIT, this );
   740 	}
   741 
   742 EXPORT_C void TMMCardArray::DeclareCardAsGone(TUint aCardNumber)
   743 /**
   744  * Clears up a card info object in the main card array
   745  */
   746 	{
   747 	OstTraceFunctionEntryExt( TMMCARDARRAY_DECLARECARDASGONE_ENTRY, this );
   748 	
   749 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mca:dcag"));
   750 	// If we thought this one was present then mark it as not present
   751 	TMMCard& card = Card(aCardNumber);
   752 	if (card.IsPresent())
   753 		{
   754 		card.iIndex=0; // Mark card as not present
   755 		iCardsPresent--;
   756 		}
   757 
   758 	// If this card is in use by a session then flag that card has now gone
   759 	if( card.iUsingSessionP != NULL )
   760 		card.iUsingSessionP->iState |= KMMCSessStateCardIsGone;
   761 
   762 	card.iUsingSessionP=NULL;
   763 	card.iSetBlockLen=0;
   764 	card.iFlags=0; 		// Reset 'has password' and 'write protected' bit fields
   765 	card.iHighSpeedClock=0;
   766 	card.iBusWidth=1;
   767 	OstTraceFunctionExit1( TMMCARDARRAY_DECLARECARDASGONE_EXIT, this );
   768 	}
   769 
   770 // return this card's index in the array or KErrNotFound if not found
   771 TInt TMMCardArray::CardIndex(const TMMCard* aCard)
   772 	{
   773 	OstTraceFunctionEntryExt( TMMCARDARRAY_CARDINDEX_ENTRY, this );
   774 	TInt i;
   775 	for (i = KMaxMMCardsPerStack-1; i>= 0; i--)
   776 		{
   777 		if (iCards[i] == aCard)
   778 			break;
   779 		}
   780 	OstTraceFunctionExitExt( TMMCARDARRAY_CARDINDEX_EXIT, this, i );
   781 	return i;
   782 	}
   783 
   784 //	--------  class TMMCCommandDesc  --------
   785 
   786 EXPORT_C TInt TMMCCommandDesc::Direction() const
   787 /**
   788  * returns -1, 0 or +1 for DT directions read, none or write respectively
   789  */
   790 	{
   791 	OstTraceFunctionEntry1( TMMCCOMMANDDESC_DIRECTION_ENTRY, this );
   792 	TUint dir = iSpec.iDirection;
   793 	TInt result = dir;
   794 	TInt ret;
   795 
   796 	if( dir == 0 )
   797 	    {
   798 	    ret = 0;
   799 		OstTraceFunctionExitExt( TMMCCOMMANDDESC_DIRECTION_EXIT1, this, ret );
   800 		return ret;
   801 	    }
   802 
   803 	if( dir & KMMCCmdDirWBitArgument )
   804 		result = TUint(iArgument) >> (dir & KMMCCmdDirIndBitPosition);
   805 
   806 	if( dir & KMMCCmdDirNegate )
   807 		result = ~result;
   808 
   809 	ret = ((result&1)-1)|1;
   810 
   811 	OstTraceFunctionExitExt( TMMCCOMMANDDESC_DIRECTION_EXIT2, this, ret );
   812 	return ret;
   813 	}
   814 
   815 
   816 TBool TMMCCommandDesc::AdjustForBlockOrByteAccess(const DMMCSession& aSession)
   817 	{
   818 	OstTraceExt2(TRACE_FLOW, TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_ENTRY, "TMMCCommandDesc::AdjustForBlockOrByteAccess;Session ID=%d;this=%x", (TInt) aSession.SessionID(), (TUint) this);
   819 /**
   820  * The MMC session provides both block and byte based IO methods, all of which can
   821  * be used on both block and byte based MMC cards.  This method adjusts the command
   822  * arguments so that they match the underlying cards access mode.
   823  *
   824  * @return ETrue if the address is valid or successfully converted, EFalse otherwise
   825  */
   826 	TUint32 blockLength = BlockLength();
   827 
   828 	if(iTotalLength == 0	||
   829 	   blockLength == 0	||
   830 	   iTotalLength % KMMCardHighCapBlockSize != 0	||	// always aligned on 512 bytes
   831 	   blockLength % KMMCardHighCapBlockSize != 0)
   832 		{
   833 		OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT1, this, (TUint) EFalse );
   834 		return EFalse;
   835 		}
   836 
   837 	if(aSession.CardP()->IsHighCapacity())
   838 		{	
   839 		// high capacity (block-based) card
   840 		if((iFlags & KMMCCmdFlagBlockAddress) == 0)
   841 			{	
   842 			// The command arguments are using byte based addressing
   843 			//  - adjust to block-based addressing
   844 			if(iArgument % KMMCardHighCapBlockSize != 0)
   845 				{
   846 				// Block based media does not support misaligned access
   847 				OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT2, this, (TUint) EFalse );
   848 				return EFalse;
   849 				}
   850 
   851 			// adjust for block based access
   852 			iArgument = iArgument >> KMMCardHighCapBlockSizeLog2;
   853 			iFlags |= KMMCCmdFlagBlockAddress;
   854 			}
   855 		}
   856 	else
   857 		{
   858 		// standard (byte based) card
   859 		if((iFlags & KMMCCmdFlagBlockAddress) != 0)
   860 			{
   861 			// The command arguments are using block based addressing
   862 			//  - adjust to byte-based addressing
   863 			const TUint32 maxBlocks = 4 * 1024 * ((1024 * 1024) >> KMMCardHighCapBlockSizeLog2);
   864 			
   865 			if(iArgument > maxBlocks)
   866 				{
   867 				// The address is out of range (>2G) - cannot convert
   868 				OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT3, this, (TUint) EFalse );
   869 				return EFalse;
   870 				}
   871 
   872 			// adjust for byte-based access
   873 			iArgument = iArgument << KMMCardHighCapBlockSizeLog2;
   874 			iFlags &= ~KMMCCmdFlagBlockAddress;
   875 			}
   876 		else if(iArgument % KMMCardHighCapBlockSize != 0)
   877 			{
   878 			// byte addressing, unaligned address
   879 			OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT4, this, (TUint) EFalse );
   880 			return EFalse;
   881 			}
   882 		}
   883 
   884 	OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT5, this, (TUint) ETrue );
   885 	return ETrue;
   886 	}
   887 
   888 void TMMCCommandDesc::Dump(TUint8* aResponseP, TMMCErr aErr)
   889 	{
   890 
   891 	Kern::Printf("------------------------------------------------------------------");
   892 	Kern::Printf("CMD %02d(0x%08x) - ",TUint(iCommand),TUint(iArgument));
   893 
   894 	switch(iCommand)
   895 		{
   896 		case 0  : Kern::Printf("                   | GO_IDLE_STATE");			break;
   897 		case 1  : Kern::Printf("                   | SEND_OP_COND");			break;
   898 		case 2  : Kern::Printf("                   | ALL_SEND_CID");			break;
   899 		case 3  : Kern::Printf("                   | SET_RELATIVE_ADDR");		break;
   900 		case 4  : Kern::Printf("                   | SET_DSR");					break;
   901 		case 5  : Kern::Printf("                   | SLEEP/AWAKE");				break;
   902 		case 6  : Kern::Printf("                   | SWITCH");					break;
   903 		case 7  : Kern::Printf("                   | SELECT/DESELECT_CARD");	break;
   904 		case 8  : Kern::Printf("                   | SEND_EXT_CSD");			break;
   905 		case 9  : Kern::Printf("                   | SEND_CSD");				break;
   906 		case 10 : Kern::Printf("                   | SEND_CID");				break;
   907 		case 11 : Kern::Printf("                   | READ_DAT_UNTIL_STOP");		break;
   908 		case 12 : Kern::Printf("                   | STOP_TRANSMISSION");		break;
   909 		case 13 : Kern::Printf("                   | SEND_STATUS");				break;
   910 		case 14 : Kern::Printf("                   | BUSTEST_R");				break;
   911 		case 15 : Kern::Printf("                   | GO_INACTIVE_STATE");		break;
   912 		case 16 : Kern::Printf("                   | SET_BLOCKLEN");			break;
   913 		case 17 : Kern::Printf("                   | READ_SINGLE_BLOCK");		break;
   914 		case 18 : Kern::Printf("                   | READ_MULTIPLE_BLOCK");		break;
   915 		case 19 : Kern::Printf("                   | BUSTEST_W");				break;
   916 		case 20 : Kern::Printf("                   | WRITE_DAT_UNTIL_STOP");	break;
   917 		case 23 : Kern::Printf("                   | SET_BLOCK_COUNT");			break;
   918 		case 24 : Kern::Printf("                   | WRITE_BLOCK");				break;
   919 		case 25 : Kern::Printf("                   | WRITE_MULTIPLE_BLOCK");	break;
   920 		case 26 : Kern::Printf("                   | PROGRAM_CID");				break;
   921 		case 27 : Kern::Printf("                   | PROGRAM_CSD");				break;
   922 		case 28 : Kern::Printf("                   | SET_WRITE_PROT");			break;
   923 		case 29 : Kern::Printf("                   | CLR_WRITE_PROT");			break;
   924 		case 30 : Kern::Printf("                   | SEND_WRITE_PROT");			break;
   925 		case 32 : Kern::Printf("                   | ERASE_WR_BLK_START");		break;	// SD
   926 		case 33 : Kern::Printf("                   | ERASE_WR_BLK_END");		break;	// SD
   927 		case 35 : Kern::Printf("                   | ERASE_GROUP_START");		break;
   928 		case 36 : Kern::Printf("                   | ERASE_GROUP_END");			break;
   929 		case 38 : Kern::Printf("                   | ERASE");					break;
   930 		case 39 : Kern::Printf("                   | FAST_IO");					break;
   931 		case 40 : Kern::Printf("                   | GO_IRQ_STATE");			break;
   932 		case 42 : Kern::Printf("                   | LOCK_UNLOCK");				break;
   933 		case 55 : Kern::Printf("                   | APP_CMD");					break;
   934 		case 56 : Kern::Printf("                   | GEN_CMD");					break;
   935 		default : Kern::Printf("                   | *** UNKNOWN COMMAND ***"); break;
   936 		}
   937 
   938 	switch(iSpec.iResponseType)
   939 		{
   940 		case ERespTypeNone:		Kern::Printf("               RSP - NONE");		break;
   941 		case ERespTypeUnknown:	Kern::Printf("               RSP - UNKNOWN");	break;
   942 		case ERespTypeR1:		Kern::Printf("               RSP - R1");		break;
   943 		case ERespTypeR1B:		Kern::Printf("               RSP - R1b");		break;
   944 		case ERespTypeR2:		Kern::Printf("               RSP - R2");		break;
   945 		case ERespTypeR3:		Kern::Printf("               RSP - R3");		break;
   946 		case ERespTypeR4:		Kern::Printf("               RSP - R4");		break;
   947 		case ERespTypeR5:		Kern::Printf("               RSP - R5");		break;
   948 		case ERespTypeR6:		Kern::Printf("               RSP - R6");		break;
   949 		default :				Kern::Printf("               RSP - *** UNKNOWN RESPONSE ***"); break;
   950 		}
   951 
   952 	switch(iSpec.iResponseLength)
   953 		{
   954 		case 0  :																				break;
   955 		case 4  : Kern::Printf("                   | 0x%08x", TMMC::BigEndian32(aResponseP));	break;
   956 		case 16 : Kern::Printf("                   | 0x%08x 0x%08x 0x%08x 0x%08x", ((TUint32*)aResponseP)[0], ((TUint32*)aResponseP)[1], ((TUint32*)aResponseP)[2], ((TUint32*)aResponseP)[3]); break;
   957 		default : Kern::Printf("                   | *** RESPONSE NOT PARSED ***");				break;
   958 		}
   959 									  Kern::Printf("               ERR - 0x%08x", aErr);
   960 	if(aErr & KMMCErrResponseTimeOut) Kern::Printf("                   | KMMCErrResponseTimeOut");
   961 	if(aErr & KMMCErrDataTimeOut)	  Kern::Printf("                   | KMMCErrDataTimeOut");
   962 	if(aErr & KMMCErrBusyTimeOut)	  Kern::Printf("                   | KMMCErrBusyTimeOut");
   963 	if(aErr & KMMCErrBusTimeOut)	  Kern::Printf("                   | KMMCErrBusTimeOut");
   964 	if(aErr & KMMCErrTooManyCards)	  Kern::Printf("                   | KMMCErrTooManyCards");
   965 	if(aErr & KMMCErrResponseCRC)	  Kern::Printf("                   | KMMCErrResponseCRC");
   966 	if(aErr & KMMCErrDataCRC)		  Kern::Printf("                   | KMMCErrDataCRC");
   967 	if(aErr & KMMCErrCommandCRC)	  Kern::Printf("                   | KMMCErrCommandCRC");
   968 	if(aErr & KMMCErrStatus)		  Kern::Printf("                   | KMMCErrStatus");
   969 	if(aErr & KMMCErrNoCard)		  Kern::Printf("                   | KMMCErrNoCard");
   970 	if(aErr & KMMCErrBrokenLock)	  Kern::Printf("                   | KMMCErrBrokenLock");
   971 	if(aErr & KMMCErrPowerDown)		  Kern::Printf("                   | KMMCErrPowerDown");
   972 	if(aErr & KMMCErrAbort)			  Kern::Printf("                   | KMMCErrAbort");
   973 	if(aErr & KMMCErrStackNotReady)	  Kern::Printf("                   | KMMCErrStackNotReady");
   974 	if(aErr & KMMCErrNotSupported)	  Kern::Printf("                   | KMMCErrNotSupported");
   975 	if(aErr & KMMCErrHardware)		  Kern::Printf("                   | KMMCErrHardware");
   976 	if(aErr & KMMCErrBusInconsistent) Kern::Printf("                   | KMMCErrBusInconsistent");
   977 	if(aErr & KMMCErrBypass)		  Kern::Printf("                   | KMMCErrBypass");
   978 	if(aErr & KMMCErrInitContext)	  Kern::Printf("                   | KMMCErrInitContext");
   979 	if(aErr & KMMCErrArgument)		  Kern::Printf("                   | KMMCErrArgument");
   980 	if(aErr & KMMCErrSingleBlock)	  Kern::Printf("                   | KMMCErrSingleBlock");
   981 	if(aErr & KMMCErrUpdPswd)		  Kern::Printf("                   | KMMCErrUpdPswd");
   982 	if(aErr & KMMCErrLocked)		  Kern::Printf("                   | KMMCErrLocked");
   983 	if(aErr & KMMCErrNotFound)		  Kern::Printf("                   | KMMCErrNotFound");
   984 	if(aErr & KMMCErrAlreadyExists)	  Kern::Printf("                   | KMMCErrAlreadyExists");
   985 	if(aErr & KMMCErrGeneral)		  Kern::Printf("                   | KMMCErrGeneral");
   986 
   987 
   988 	if(iSpec.iResponseType == ERespTypeR1 || iSpec.iResponseType == ERespTypeR1B)
   989 		{
   990 		const TUint32 stat = TMMC::BigEndian32(aResponseP);
   991 		
   992 											 Kern::Printf("              STAT - 0x%08x", stat);
   993 		if(stat & KMMCStatAppCmd)			 Kern::Printf("                   | KMMCStatAppCmd");
   994 		if(stat & KMMCStatSwitchError)		 Kern::Printf("                   | KMMCStatSwitchError");
   995 		if(stat & KMMCStatReadyForData)		 Kern::Printf("                   | KMMCStatReadyForData");
   996 		if(stat & KMMCStatCurrentStateMask){ Kern::Printf("                   | KMMCStatCurrentStateMask");
   997 											 const TMMCardStateEnum cardState = (TMMCardStateEnum)(stat & KMMCStatCurrentStateMask);
   998 											 switch (cardState){
   999 												 case ECardStateIdle  : Kern::Printf("                     | ECardStateIdle"); break;
  1000 												 case ECardStateReady : Kern::Printf("                     | ECardStateReady"); break;
  1001 												 case ECardStateIdent : Kern::Printf("                     | ECardStateIdent"); break;
  1002 												 case ECardStateStby  : Kern::Printf("                     | ECardStateStby"); break;
  1003 												 case ECardStateTran  : Kern::Printf("                     | ECardStateTran"); break;
  1004 												 case ECardStateData  : Kern::Printf("                     | ECardStateData"); break;
  1005 												 case ECardStateRcv   : Kern::Printf("                     | ECardStateRcv"); break;
  1006 												 case ECardStatePrg   : Kern::Printf("                     | ECardStatePrg"); break;
  1007 												 case ECardStateDis   : Kern::Printf("                     | ECardStateDis"); break;
  1008 												 case ECardStateBtst  : Kern::Printf("                     | ECardStateBtst"); break;
  1009 												 case ECardStateSlp   : Kern::Printf("                     | ECardStateSlp"); break;
  1010 												 default   	 		  : Kern::Printf("                     | ECardStateUnknown"); break;
  1011 											 }
  1012 										   }
  1013 		if(stat & KMMCStatEraseReset)		 Kern::Printf("                   | KMMCStatEraseReset");
  1014 		if(stat & KMMCStatCardECCDisabled)	 Kern::Printf("                   | KMMCStatCardECCDisabled");
  1015 		if(stat & KMMCStatWPEraseSkip)		 Kern::Printf("                   | KMMCStatWPEraseSkip");
  1016 		if(stat & KMMCStatErrCSDOverwrite)	 Kern::Printf("                   | KMMCStatErrCSDOverwrite");
  1017 		if(stat & KMMCStatErrOverrun)		 Kern::Printf("                   | KMMCStatErrOverrun");
  1018 		if(stat & KMMCStatErrUnderrun)		 Kern::Printf("                   | KMMCStatErrUnderrun");
  1019 		if(stat & KMMCStatErrUnknown)		 Kern::Printf("                   | KMMCStatErrUnknown");
  1020 		if(stat & KMMCStatErrCCError)		 Kern::Printf("                   | KMMCStatErrCCError");
  1021 		if(stat & KMMCStatErrCardECCFailed)  Kern::Printf("                   | KMMCStatErrCardECCFailed");
  1022 		if(stat & KMMCStatErrIllegalCommand) Kern::Printf("                   | KMMCStatErrIllegalCommand");
  1023 		if(stat & KMMCStatErrComCRCError)	 Kern::Printf("                   | KMMCStatErrComCRCError");
  1024 		if(stat & KMMCStatErrLockUnlock)	 Kern::Printf("                   | KMMCStatErrLockUnlock");
  1025 		if(stat & KMMCStatCardIsLocked)		 Kern::Printf("                   | KMMCStatCardIsLocked");
  1026 		if(stat & KMMCStatErrWPViolation)	 Kern::Printf("                   | KMMCStatErrWPViolation");
  1027 		if(stat & KMMCStatErrEraseParam)	 Kern::Printf("                   | KMMCStatErrEraseParam");
  1028 		if(stat & KMMCStatErrEraseSeqError)  Kern::Printf("                   | KMMCStatErrEraseSeqError");
  1029 		if(stat & KMMCStatErrBlockLenError)  Kern::Printf("                   | KMMCStatErrBlockLenError");
  1030 		if(stat & KMMCStatErrAddressError)	 Kern::Printf("                   | KMMCStatErrAddressError");
  1031 		if(stat & KMMCStatErrOutOfRange)	 Kern::Printf("                   | KMMCStatErrOutOfRange");
  1032 		}
  1033 
  1034 	Kern::Printf("                   -----------------------------------------------");
  1035 	}
  1036 
  1037 //	--------  class TMMCRCAPool  --------
  1038 
  1039 TRCA TMMCRCAPool::GetFreeRCA()
  1040 /**
  1041  * Returns a free RCA number from the pool or zero if none is available
  1042  */
  1043 	{
  1044 	OstTraceFunctionEntry1( TMMCRCAPOOL_GETFREERCA_ENTRY, this );
  1045 	TUint32 seekm = (iPool | iLocked) + 1;
  1046 	iPool |= (seekm & ~iLocked);
  1047 	TUint16 ret;
  1048 	
  1049 	if( (seekm & 0xFFFFFFFF) == 0 )
  1050 	    {
  1051 	    ret = 0;
  1052 		OstTraceFunctionExitExt( TMMCRCAPOOL_GETFREERCA_EXIT1, this, (TUint) ret);
  1053 		return ret;
  1054 	    }
  1055 
  1056 	TUint16 pos = 1;
  1057 
  1058 	if ((seekm & 0xFFFF) == 0)	{ seekm >>= 16;	pos = 17; }
  1059 	if ((seekm & 0xFF) == 0)	{ seekm >>= 8;	pos += 8; }
  1060 	if ((seekm & 0xF) == 0)		{ seekm >>= 4;	pos += 4; }
  1061 	if ((seekm & 0x3) == 0)		{ seekm >>= 2;	pos += 2; }
  1062 	if ((seekm & 0x1) == 0)		pos++;
  1063 
  1064 	// Multiply return value by 257 so that 1 is never returned.  (0x0001 is the default RCA value.)
  1065 	// The RCA integer value is divided by 257 in LockRCA() and UnlockRCA() to compensate
  1066 	// for this adjustment.  These functions are only ever called in this file with the iRCA
  1067 	// field of a TMMCard object, and not with arbitrary values.
  1068 	// The iRCA field itself is only assigned values from iNewCards[] or zero.  iNewCards
  1069 	// in turn is fed values from this function, in DMMCStack::CIMUpdateAcqSM() / EStSendCIDIssued.
  1070 
  1071 	ret = TUint16(pos << 8 | pos);
  1072 	OstTraceFunctionExitExt( TMMCRCAPOOL_GETFREERCA_EXIT2, this, (TUint) ret);
  1073 	return ret;
  1074 	}
  1075 
  1076 
  1077 
  1078 //	--------  class TMMCSessRing  --------
  1079 
  1080 TMMCSessRing::TMMCSessRing()
  1081 /**
  1082  * Constructor
  1083  */
  1084 	: iPMark(NULL),iPoint(NULL),iPrevP(NULL),iSize(0)
  1085 	{OstTraceFunctionEntry1( TMMCSESSRING_TMMCSESSRING_ENTRY, this );}
  1086 
  1087 
  1088 void TMMCSessRing::Erase()
  1089 /**
  1090  * Erases all the ring content
  1091  */
  1092 	{
  1093 	OstTraceFunctionEntry1( TMMCSESSRING_ERASE_ENTRY, this );
  1094 	iPMark = iPoint = iPrevP = NULL; iSize = 0;
  1095 	OstTraceFunctionExit1( TMMCSESSRING_ERASE_EXIT, this );
  1096 	}
  1097 
  1098 
  1099 DMMCSession* TMMCSessRing::operator++(TInt)
  1100 /**
  1101  * Post increment of Point
  1102  */
  1103 	{
  1104 	if( iPoint == NULL )
  1105 		return( NULL );
  1106 
  1107 	if( (iPrevP=iPoint) == iPMark )
  1108 		iPoint = NULL;
  1109 	else
  1110 		iPoint = iPoint->iLinkP;
  1111 
  1112 	return( iPrevP );
  1113 	}
  1114 
  1115 
  1116 TBool TMMCSessRing::Point(DMMCSession* aSessP)
  1117 /**
  1118  * Finds aSessP and sets Point to that position
  1119  */
  1120 	{
  1121 	OstTraceFunctionEntryExt( TMMCSESSRING_POINT_ENTRY, this );
  1122 	Point();
  1123 
  1124 	while( iPoint != NULL )
  1125 		if( iPoint == aSessP )
  1126 		    {
  1127 			OstTraceFunctionExitExt( TMMCSESSRING_POINT_EXIT1, this, (TUint) ETrue );
  1128 			return ETrue;
  1129 		    }
  1130 		else
  1131 			this->operator++(0);
  1132 
  1133 	OstTraceFunctionExitExt( TMMCSESSRING_POINT_EXIT2, this, (TUint) EFalse );
  1134 	return EFalse;
  1135 	}
  1136 
  1137 void TMMCSessRing::Add(DMMCSession* aSessP)
  1138 /**
  1139  * Inserts aSessP before Marker. Point is moved into the Marker position.
  1140  */
  1141 	{
  1142 	OstTraceFunctionEntryExt( TMMCSESSRING_ADD1_ENTRY, this );
  1143 	if( iSize == 0 )
  1144 		{
  1145 		iPMark = iPrevP = iPoint = aSessP;
  1146 		aSessP->iLinkP = aSessP;
  1147 		iSize = 1;
  1148 		OstTraceFunctionExit1( TMMCSESSRING_ADD1_EXIT1, this );
  1149 		return;
  1150 		}
  1151 
  1152 	iPoint = iPMark->iLinkP;
  1153 	iPMark->iLinkP = aSessP;
  1154 	aSessP->iLinkP = iPoint;
  1155 	iPMark = iPrevP = aSessP;
  1156 	iSize++;
  1157 	OstTraceFunctionExit1( TMMCSESSRING_ADD1_EXIT2, this );
  1158 	}
  1159 
  1160 
  1161 void TMMCSessRing::Add(TMMCSessRing& aRing)
  1162 /**
  1163  * Inserts aRing before Marker. Point is moved into the Marker position.
  1164  * aRing Marker becomes the fisrt inserted element.
  1165  * Erases aRing.
  1166  */
  1167 	{
  1168 	OstTraceFunctionEntry1( TMMCSESSRING_ADD2_ENTRY, this );
  1169 	Point();
  1170 
  1171 	if( aRing.iSize == 0 )
  1172 	    {
  1173 		OstTraceFunctionExit1( TMMCSESSRING_ADD2_EXIT1, this );
  1174 		return;
  1175 	    }
  1176 
  1177 	if( iSize == 0 )
  1178 		{
  1179 		iPrevP = iPMark = aRing.iPMark;
  1180 		iPoint = iPrevP->iLinkP;
  1181 		iSize = aRing.iSize;
  1182 		}
  1183 	else
  1184 		{
  1185 		iPrevP->iLinkP = aRing.iPMark->iLinkP;
  1186 		iPMark = iPrevP = aRing.iPMark;
  1187 		iPrevP->iLinkP = iPoint;
  1188 		iSize += aRing.iSize;
  1189 		}
  1190 
  1191 	aRing.Erase();
  1192 	OstTraceFunctionExit1( TMMCSESSRING_ADD2_EXIT2, this );
  1193 	}
  1194 
  1195 DMMCSession* TMMCSessRing::Remove()
  1196 /**
  1197  * Removes an element pointed to by Point.
  1198  * Point (and possibly Marker) move forward as in operator++
  1199  */
  1200 	{
  1201 	OstTraceFunctionEntry1( TMMCSESSRING_REMOVE1_ENTRY, this );
  1202 	DMMCSession* remS = iPrevP;
  1203 
  1204 	if( iSize < 2 )
  1205 		Erase();
  1206 	else
  1207 		{
  1208 		remS = remS->iLinkP;
  1209 		iPrevP->iLinkP = remS->iLinkP;
  1210 		iSize--;
  1211 
  1212 		if( iPoint != NULL )
  1213 			iPoint = iPrevP->iLinkP;
  1214 
  1215 		if( iPMark == remS )
  1216 			{
  1217 			iPMark = iPrevP;
  1218 			iPoint = NULL;
  1219 			}
  1220 		}
  1221 
  1222 	OstTraceFunctionExitExt( TMMCSESSRING_REMOVE1_EXIT, this, ( TUint )( remS ) );
  1223 	return remS;
  1224 	}
  1225 
  1226 
  1227 void TMMCSessRing::Remove(DMMCSession* aSessP)
  1228 /**
  1229  * Removes a specified session from the ring
  1230  */
  1231 	{
  1232 	OstTraceFunctionEntryExt( TMMCSESSRING_REMOVE2_ENTRY, this );
  1233 	if( Point(aSessP) )
  1234 		Remove();
  1235 	else
  1236 		DMMCSocket::Panic(DMMCSocket::EMMCSessRingNoSession);
  1237 	OstTraceFunctionExit1( TMMCSESSRING_REMOVE2_EXIT, this );
  1238 	}
  1239 
  1240 
  1241 
  1242 //	--------  class TMMCStateMachine  --------
  1243 
  1244 
  1245 /**
  1246 Removes all state from the state machine.
  1247 
  1248 It also resets the stack and the exit code.
  1249 */
  1250 EXPORT_C void TMMCStateMachine::Reset()
  1251 	{
  1252 	OstTraceFunctionEntry1( TMMCSTATEMACHINE_RESET_ENTRY, this );
  1253 	iAbort = EFalse;
  1254 	iSP = 0; iExitCode = 0;
  1255 	iStack[0].iState = 0; iStack[0].iTrapMask = 0;
  1256 	OstTraceFunctionExit1( TMMCSTATEMACHINE_RESET_EXIT, this );
  1257 	}
  1258 
  1259 
  1260 
  1261 
  1262 /**
  1263 The state machine dispatcher.
  1264 
  1265 @return The MultiMediaCard error code. 
  1266 */
  1267 EXPORT_C TMMCErr TMMCStateMachine::Dispatch()
  1268 	{
  1269 	OstTraceFunctionEntry1( TMMCSTATEMACHINE_DISPATCH_ENTRY, this );
  1270 	
  1271 	// If a state machine returns non-zero, i.e. a non-empty error set, then the second
  1272 	// inner while loop is broken.  The errors are thrown like an exception where the
  1273 	// stack is unravelled until it reaches a state machine which can handle at least
  1274 	// one of the error codes, else this function returns with the exit code or'd with
  1275 	// KMMCErrBypass.  If the state machine returns zero, then this function returns
  1276 	// zero if iSuspend is set, i.e., if the stack is waiting on an asynchronous event.
  1277 	// If suspend is not set, then the next state machine is called.  This may be the
  1278 	// same as the current state machine, or its caller if the current state machine
  1279 	// ended called Pop() before exiting, e.g., via SMF_END.
  1280 
  1281 	while( iSP >= 0 && !iAbort )
  1282 		{
  1283 		// If there is an un-trapped error, wind back down the stack, either
  1284 		// to the end of the stack or until the error becomes trapped.
  1285 		while( iSP >= 0 && (iExitCode & ~iStack[iSP].iTrapMask) != 0 )
  1286 			iSP--;
  1287 
  1288 		iExitCode &= ~KMMCErrBypass;
  1289 
  1290 		if ( iExitCode )
  1291 			{
  1292 			__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Err %x",iExitCode));
  1293 			OstTrace1( TRACE_INTERNALS, TMMCSTATEMACHINE_DISPATCH, "iExitCode=0x%x", iExitCode );
  1294 			}
  1295 
  1296 		while( iSP >= 0 && !iAbort )
  1297 			{
  1298 			__KTRACE_OPT(KPBUS1,Kern::Printf("-msm:dsp:%02x:%08x.%02x",iSP, TUint32(iStack[iSP].iFunction), State()));
  1299 			OstTraceExt3( TRACE_INTERNALS, TMMCSTATEMACHINE_DISPATCH2, "iSP=%d; iStack[iSP].iFunction=0x%08x; State=0x%02x", (TInt) iSP, (TUint) iStack[iSP].iFunction, (TUint) State() );
  1300 
  1301 			iSuspend = ETrue;
  1302 			const TMMCErr signal = iStack[iSP].iFunction(iContextP);
  1303 
  1304 			if (signal)
  1305 				{
  1306 				iExitCode = signal;
  1307 				break;
  1308 				}
  1309 
  1310 			if( iSuspend )
  1311 				{
  1312 				__KTRACE_OPT(KPBUS1,Kern::Printf("<msm:dsp:exitslp"));
  1313 				OstTraceFunctionExit1( TMMCSTATEMACHINE_DISPATCH_EXIT1, this );
  1314 				return(0);
  1315 				}
  1316 			}
  1317 		}
  1318 
  1319 	__KTRACE_OPT(KPBUS1,Kern::Printf("<msm:dsp:exit%08x", iExitCode));
  1320 	OstTraceFunctionExit1( TMMCSTATEMACHINE_DISPATCH_EXIT2, this );
  1321 	return( KMMCErrBypass | iExitCode );
  1322 	}
  1323 
  1324 
  1325 
  1326 
  1327 /**
  1328 Pushes another state machine entry onto the stack.
  1329 
  1330 Typically, this is invoked using one of the macros:
  1331 SMF_CALL, SMF_CALLWAIT, SMF_INVOKES, SMF_INVOKEWAITS 
  1332 
  1333 @param anEntry  The state machine function to be run; this will start at
  1334                 the initial state (EStBegin), with no exception handling defined.
  1335 @param aSuspend Indicates whether the state machine is to block on return to the dispatcher;
  1336                 Specify ETrue to block; EFalse not to block.
  1337                 EFalse is the default, if not explicitly stated.
  1338 
  1339 @return KMMCErrNone
  1340 
  1341 @panic PBUS-MMC 0 if the maximum depth of nested state machine entries is being exeeded.
  1342 
  1343 @see SMF_CALL
  1344 @see SMF_CALLWAIT
  1345 @see SMF_INVOKES
  1346 @see SMF_INVOKEWAITS 
  1347 */
  1348 EXPORT_C TMMCErr TMMCStateMachine::Push(TMMCErr (*anEntry)(TAny*), TBool aSuspend)
  1349 	{
  1350 	OstTraceFunctionEntry1( TMMCSTATEMACHINE_PUSH_ENTRY, this );
  1351 	iSP++;
  1352 	__ASSERT_ALWAYS(TUint(iSP)<KMaxMMCMachineStackDepth,
  1353 		DMMCSocket::Panic(DMMCSocket::EMMCMachineStack));
  1354 	iStack[iSP].iFunction = anEntry;
  1355 	iStack[iSP].iState = 0;
  1356 	iStack[iSP].iTrapMask = 0;
  1357 	if( !aSuspend )
  1358 		iSuspend = EFalse;
  1359 	OstTraceFunctionExit1( TMMCSTATEMACHINE_PUSH_EXIT, this );
  1360 	return 0;
  1361 	}
  1362 
  1363 
  1364 
  1365 
  1366 /**
  1367 Jumps to the specified state machine function in the current state machine entry.
  1368 
  1369 @param anEntry  The state machine function to be run; this will start at
  1370                 the initial state (EStBegin), with no exception handling defined.
  1371 @param aSuspend Indicates whether the state machine is to block on return to the dispatcher;
  1372                 Specify ETrue to block; EFalse not to block.
  1373                 EFalse is the default, if not explicitly stated.
  1374 
  1375 @return KMMCErrNone
  1376 */
  1377 EXPORT_C TMMCErr TMMCStateMachine::Jump(TMMCErr (*anEntry)(TAny*), TBool aSuspend)
  1378 	{
  1379 	OstTraceFunctionEntry1( TMMCSTATEMACHINE_JUMP_ENTRY, this );
  1380 	iStack[iSP].iFunction = anEntry;
  1381 	iStack[iSP].iState = 0;
  1382 	iStack[iSP].iTrapMask = 0;
  1383 	if( !aSuspend )
  1384 		iSuspend = EFalse;
  1385 	OstTraceFunctionExit1( TMMCSTATEMACHINE_JUMP_EXIT, this );
  1386 	return 0;
  1387 	}
  1388 
  1389 
  1390 
  1391 
  1392 //	--------  class DMMCStack  --------
  1393 
  1394 #pragma warning( disable : 4355 )	// this used in initializer list
  1395 EXPORT_C DMMCStack::DMMCStack(TInt /*aBus*/, DMMCSocket* aSocket)
  1396 /**
  1397  * Constructs a DMMCStack object
  1398  * @param aBus Unused
  1399  * @param aSocket A pointer to the associated socket.
  1400  */
  1401 	: iWorkSet(),
  1402 	iReadyQueue(),
  1403 	iEntryQueue(),
  1404 	iStackDFC(DMMCStack::StackDFC, this, 1),
  1405 	iSelectedCard(TUint16(~0)),
  1406 	iSocket(aSocket),
  1407 	iStackSession(NULL),
  1408 	iAutoUnlockSession(TMMCCallBack(AutoUnlockCBST, this)),
  1409 	iInitState(EISPending),
  1410 	iInitialise(ETrue),
  1411 	iCurrentDSR(),
  1412 	iConfig(),
  1413 	iRCAPool(),
  1414 	iMasterConfig()
  1415 	{
  1416 //	iStackState(0),
  1417 //	iLockingSessionP(NULL),
  1418 //	iAttention(EFalse),
  1419 //	iAbortReq(EFalse),
  1420 //	iCompReq(EFalse),
  1421 //	iDoorOpened(EFalse),
  1422 //	iPoweredUp(EFalse),
  1423 //	iDFCRunning(EFalse),
  1424 //	iAbortAll(EFalse),
  1425 //	iAllExitCode(0),
  1426 //	iSessionP(NULL),
  1427 //	iCurrentOpRange(0),
  1428 //	iCardsPresent(0),
  1429 //	iMaxCardsInStack(0)
  1430 	}
  1431 #pragma warning( default : 4355 )
  1432 
  1433 EXPORT_C TInt DMMCStack::Init()
  1434 /**
  1435  * Initialises the generic MMC stack.
  1436  * @return KErrNone if successful, standard error code otherwise.
  1437  */
  1438 	{
  1439 	OstTraceFunctionEntry1( DMMCSTACK_INIT_ENTRY, this );
  1440 	// allocate and initialize session object
  1441 	if ((iStackSession = AllocSession(TMMCCallBack(StackSessionCBST, this))) == 0)
  1442 	    {
  1443 		OstTraceFunctionExitExt( DMMCSTACK_INIT_EXIT1, this, KErrNoMemory );
  1444 		return KErrNoMemory;
  1445 	    }
  1446 
  1447 	// create helper class
  1448 	if ((iBody = new DBody(*this)) == NULL)
  1449 	    {
  1450 		OstTraceFunctionExitExt( DMMCSTACK_INIT_EXIT2, this, KErrNoMemory );
  1451 		return KErrNoMemory;
  1452 	    }
  1453 
  1454 	iStackSession->SetStack(this);
  1455 
  1456 	iStackDFC.SetDfcQ(&iSocket->iDfcQ);
  1457 
  1458 	// Get the maximal number of cards from ASSP layer
  1459 	iMaxCardsInStack = iSocket->TotalSupportedCards();
  1460 	if ( iMaxCardsInStack > KMaxMMCardsPerStack )
  1461 		iMaxCardsInStack=KMaxMMCardsPerStack;
  1462 
  1463 	TInt r = iCardArray->AllocCards();
  1464 
  1465 	OstTraceFunctionExitExt( DMMCSTACK_INIT_EXIT3, this, r );
  1466 	return r;
  1467 	}
  1468 
  1469 EXPORT_C void DMMCStack::PowerUpStack()
  1470 /**
  1471  * Enforce stack power-up and initialisation.
  1472  * This is an asynchronous operation, which calls DMMCSocket::PowerUpSequenceComplete upon completion.
  1473  */
  1474 	{
  1475 	OstTraceFunctionEntry1( DMMCSTACK_POWERUPSTACK_ENTRY, this );
  1476 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:pus"));
  1477 
  1478 	if (iPSLBuf == NULL)
  1479 		{
  1480 		GetBufferInfo(&iPSLBuf, &iPSLBufLen);
  1481 		iMinorBufLen = KMinMinorBufSize;
  1482 		}
  1483 
  1484 	ReportPowerDown();							// ensure power will be switch on regardless
  1485 
  1486 	Scheduler( iInitialise );
  1487 	OstTraceFunctionExit1( DMMCSTACK_POWERUPSTACK_EXIT, this );
  1488 	}
  1489 
  1490 void DMMCStack::QSleepStack()
  1491 /**
  1492  * Schedules a session to place media in Sleep State
  1493  */
  1494 	{
  1495 	OstTraceFunctionEntry1( DMMCSTACK_QSLEEPSTACK_ENTRY, this );
  1496 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:qsleep"));
  1497 
  1498 	Scheduler( iSleep );
  1499 	OstTraceFunctionExit1( DMMCSTACK_QSLEEPSTACK_EXIT, this );
  1500 	}
  1501 
  1502 EXPORT_C void DMMCStack::PowerDownStack()
  1503 /**
  1504  * Enforce stack power down.
  1505  * Clients generally shouldn't need to concern themselves with powering down a stack 
  1506  * unless they specifically need to perform a power reset of a card.  If a driver fails to 
  1507  * open then normal practise is for that driver to leave the card powered so that any subsequent 
  1508  * driver which may attempt to open immediately after this failed attempt won't have to re-power the card. 
  1509  * If no driver successfully opens on the card then the Controllers inactivity/not in use 
  1510  * timeout system can be left to power it down.
  1511  */
  1512 	{
  1513 	OstTraceFunctionEntry1( DMMCSTACK_POWERDOWNSTACK_ENTRY, this );
  1514 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:pds"));
  1515 
  1516 	ReportPowerDown();
  1517 	iInitState = EISPending;
  1518 	DoPowerDown();
  1519 
  1520 	TBool cardRemoved = (iStackState & KMMCStackStateCardRemoved);
  1521 	for (TUint i=0;i<iMaxCardsInStack;i++)
  1522 		{
  1523 		TMMCard& card = iCardArray->Card(i);
  1524 		card.SetBusWidth(1);
  1525 		card.SetHighSpeedClock(0);
  1526 		if (cardRemoved)
  1527 			{
  1528 		    iCardArray->DeclareCardAsGone(i);
  1529 			}
  1530 		else
  1531 			{
  1532 			// set the locked bit if the card has a password - need to do this 
  1533 			// now that RLocalDrive::Caps() no longer powers up the stack
  1534 			if (card.HasPassword())
  1535 				{
  1536 				TMapping* pmp = iSocket->iPasswordStore->FindMappingInStore(card.CID());
  1537 				if (!pmp || pmp->iState != TMapping::EStValid)
  1538 					{
  1539 					*((TUint32*) &card.iStatus) |= KMMCStatCardIsLocked;
  1540 					}
  1541 				}
  1542 			
  1543 			// Remove card state flags, after a power cycle all cards are in idle state
  1544 			*((TUint32*) &card.iStatus) &= ~KMMCStatCurrentStateMask;
  1545 			}
  1546 		}
  1547 	if (cardRemoved)
  1548 	    iStackState &= ~KMMCStackStateCardRemoved;
  1549 
  1550 
  1551 	iSocket->iVcc->SetState(EPsuOff);
  1552 	if (iSocket->iVccCore)
  1553 		iSocket->iVccCore->SetState(EPsuOff);
  1554 
  1555 	// Cancel timers, reset ASSP, cancel stack DFC & remove session from workset 
  1556 	// to ensure stack doesn't wake up again & attempt to dereference iSessionP
  1557  	if (iSessionP)
  1558 		Abort(iSessionP);
  1559 
  1560 	iStackDFC.Cancel();
  1561 
  1562 	// The stack may have powered down while attempting to power up (e.g. because a card has not responded), 
  1563 	// so ensure stack doesn't attempt to initialize itself again until next PowerUpStack()
  1564 	iInitialise = EFalse;
  1565 	iStackState &= ~(KMMCStackStateInitInProgress | KMMCStackStateInitPending | KMMCStackStateBusInconsistent | KMMCStackStateWaitingDFC);
  1566 	iSessionP = NULL;
  1567 	OstTraceFunctionExit1( DMMCSTACK_POWERDOWNSTACK_EXIT, this );
  1568 	}
  1569 
  1570 //
  1571 // DMMCStack:: --- Stack Scheduler and its supplementary functions ---
  1572 //
  1573 DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedGetOnDFC()
  1574 /**
  1575  * Initiates stack DFC. Returns either Continue or Loop.
  1576  */
  1577 	{
  1578 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDGETONDFC_ENTRY, this );
  1579 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sgd"));
  1580 
  1581 	if( iDFCRunning )
  1582 	    {
  1583 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDGETONDFC_EXIT1, this, (TInt) ESchedContinue);
  1584 		return ESchedContinue;
  1585 	    }
  1586 
  1587 	if( (iStackState & KMMCStackStateWaitingDFC) == 0 )
  1588 		{
  1589 		__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sgd:q"));
  1590 		iStackState |= KMMCStackStateWaitingDFC;
  1591 		if (NKern::CurrentContext()==NKern::EInterrupt)
  1592 			iStackDFC.Add();
  1593 		else
  1594 			iStackDFC.Enque();
  1595 		}
  1596 
  1597 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDGETONDFC_EXIT2, this, (TInt) ESchedLoop);
  1598 	return ESchedLoop;
  1599 	}
  1600 
  1601 void DMMCStack::SchedSetContext(DMMCSession* aSessP)
  1602 /**
  1603  * Sets up the specified session as the current session.
  1604  * Invoked by JobChooser and Initialiser.
  1605  * @param aSessP A pointer to the session.
  1606  */
  1607 	{
  1608 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDSETCONTEXT_ENTRY, this );
  1609 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ssc"));
  1610 
  1611 	if( (iStackState & (KMMCStackStateInitPending|KMMCStackStateBusInconsistent)) != 0 &&
  1612 		aSessP->iSessionID != ECIMInitStack )
  1613 		{
  1614 		iInitialise = ETrue;
  1615 		OstTraceFunctionExit1( DMMCSTACK_SCHEDSETCONTEXT_EXIT1, this );
  1616 		return;
  1617 		}
  1618 
  1619 	if( iSessionP != aSessP )
  1620 		{
  1621 		iStackState |= KMMCStackStateReScheduled;
  1622 		MergeConfig( aSessP );
  1623 
  1624 		if( aSessP->iSessionID == ECIMInitStack )
  1625 			iInitialise = ETrue;
  1626 		else
  1627 			if( InitStackInProgress() )
  1628 				MarkComplete( aSessP, KMMCErrStackNotReady );
  1629 			else
  1630 				if( aSessP->iBrokenLock )
  1631 					MarkComplete( aSessP, KMMCErrBrokenLock );
  1632 
  1633 		iSessionP = aSessP;
  1634 		}
  1635 
  1636 	iSessionP->iState &= ~KMMCSessStateDoReSchedule;
  1637 	OstTraceFunctionExit1( DMMCSTACK_SCHEDSETCONTEXT_EXIT2, this );
  1638 	}
  1639 
  1640 void DMMCStack::SchedDoAbort(DMMCSession* aSessP)
  1641 /**
  1642  * Aborts asynchronous activities of a session aSessP
  1643  * @param aSessP A pointer to the session to be aborted.
  1644  */
  1645 	{
  1646 	OstTraceFunctionEntryExt( DMMCSTACK_SCHEDDOABORT_ENTRY, this );
  1647 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sda"));
  1648 
  1649 #ifdef __EPOC32__
  1650 	if( aSessP->iBlockOn & KMMCBlockOnPollTimer )
  1651 		aSessP->iPollTimer.Cancel();
  1652 
  1653 	if( aSessP->iBlockOn & KMMCBlockOnRetryTimer )
  1654 		aSessP->iRetryTimer.Cancel();
  1655 
  1656 	if( aSessP->iBlockOn & KMMCBlockOnPgmTimer )
  1657 		aSessP->iProgramTimer.Cancel();
  1658 #endif	// #ifdef __EPOC32__
  1659 
  1660 	if( aSessP->iBlockOn & KMMCBlockOnWaitToLock )
  1661 		iStackState &= ~KMMCStackStateWaitingToLock;
  1662 
  1663 	if( aSessP->iBlockOn & (KMMCBlockOnASSPFunction | KMMCBlockOnInterrupt | KMMCBlockOnDataTransfer) )
  1664 		ASSPReset();
  1665 
  1666 	if( (aSessP->iState & (KMMCSessStateInProgress|KMMCSessStateCritical)) ==
  1667 		 (KMMCSessStateInProgress|KMMCSessStateCritical) )
  1668 		iStackState |= KMMCStackStateInitPending;
  1669 	
  1670 	
  1671 	(void)__e32_atomic_and_ord32(&aSessP->iBlockOn, ~(KMMCBlockOnPollTimer | KMMCBlockOnRetryTimer |
  1672 						  							  KMMCBlockOnWaitToLock | KMMCBlockOnASSPFunction | 
  1673 						  							  KMMCBlockOnInterrupt | KMMCBlockOnDataTransfer) );
  1674 	OstTraceFunctionExit1( DMMCSTACK_SCHEDDOABORT_EXIT, this );
  1675 	}
  1676 
  1677 DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedResolveStatBlocks(DMMCSession* aSessP)
  1678 /**
  1679  * Checks static blocking conditions and removes them as necessary
  1680  * @param aSessP A pointer to the session.
  1681  * @return EschedContinue or ESchedLoop (if scheduler is to be restarted)
  1682  */
  1683 	{
  1684 	OstTraceFunctionEntryExt( DMMCSTACK_SCHEDRESOLVESTATBLOCKS_ENTRY, this );
  1685 
  1686 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:srsb"));
  1687 
  1688 	if( (aSessP->iBlockOn & KMMCBlockOnCardInUse) && aSessP->iCardP->iUsingSessionP == NULL )
  1689 		aSessP->SynchUnBlock( KMMCBlockOnCardInUse );
  1690 
  1691 	if( (aSessP->iBlockOn & KMMCBlockOnWaitToLock) && iWorkSet.Size() == 1 )
  1692 		{
  1693 		// ECIMLockStack processed here
  1694 		iLockingSessionP = aSessP;					// in this order
  1695 		iStackState &= ~KMMCStackStateWaitingToLock;
  1696 		aSessP->SynchUnBlock( KMMCBlockOnWaitToLock );
  1697 		MarkComplete( aSessP, KMMCErrNone );
  1698 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDRESOLVESTATBLOCKS_EXIT1, this, (TInt) ESchedLoop );
  1699 		return ESchedLoop;
  1700 		}
  1701 
  1702 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDRESOLVESTATBLOCKS_EXIT2, this, (TInt) ESchedContinue );
  1703 	return ESchedContinue;
  1704 	}
  1705 
  1706 DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedGroundDown(DMMCSession* aSessP, TMMCErr aReason)
  1707 /**
  1708  * Aborts all asynchronous activities of session aSessP with
  1709  * iExitCode = aReason. This function conserns itself with asynchronous
  1710  * activities only; session static state (eg Critical) is not taken into
  1711  * account. Session dynamic state and action flags (i.e. SafeInGaps,
  1712  * DoReSchedule and DoDFC) are cleared.
  1713  * @param aSessP A pointer to the session.
  1714  * @param aReason The reason for aborting.
  1715  * @return EschedContinue if everything's done OK.
  1716  * @return ESchedLoop if the session can not be safely grounded (eg
  1717  * iStackSession) and should therefore be aborted and/or completed by a
  1718  * separate scheduler pass.
  1719  */
  1720 	{
  1721 	OstTraceExt3(TRACE_FLOW, DMMCSTACK_SCHEDGROUNDDOWN_ENTRY, "DMMCStack::SchedGroundDown;aSessionP=%x;aReason=%d;this=%x", (TUint) aSessP, (TInt) aReason, (TUint) this);
  1722 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sgdn"));
  1723 
  1724 	if( (aSessP == iStackSession) || InitStackInProgress() )
  1725 	    {
  1726 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDGROUNDDOWN_EXIT1, this, (TInt) ESchedLoop );
  1727 		return ESchedLoop;
  1728 	    }
  1729 	
  1730 	if( aSessP->iState & KMMCSessStateInProgress )
  1731 		{
  1732 		SchedDoAbort( aSessP );
  1733 		//coverity[check_return]
  1734 		//return value is not saved or checked because there is no further uses.
  1735 		aSessP->iMachine.SetExitCode( aReason );
  1736 		aSessP->iState &= ~(KMMCSessStateSafeInGaps | KMMCSessStateDoReSchedule |
  1737 							KMMCSessStateDoDFC);
  1738 		}
  1739 
  1740 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDGROUNDDOWN_EXIT2, this, (TInt) ESchedContinue );
  1741 	return ESchedContinue;
  1742 	}
  1743 
  1744 DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedEnqueStackSession(TMMCSessionTypeEnum aSessID)
  1745 /**
  1746  * Prepare internal session for InitStack and enque it into WorkSet.
  1747  * @return EschedContinue or ESchedLoop
  1748  */
  1749 	{
  1750 	OstTraceExt2(TRACE_FLOW, DMMCSTACK_SCHEDENQUESTACKSESSION_ENTRY ,"DMMCStack::SchedEnqueStackSession;aSessID=%d;this=%x", (TInt) aSessID, (TUint) this);
  1751 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sess"));
  1752 
  1753 		if( iStackSession->IsEngaged() )
  1754 			{
  1755 			MarkComplete( iStackSession, KMMCErrAbort );
  1756 			OstTraceFunctionExitExt( DMMCSTACK_SCHEDENQUESTACKSESSION_EXIT1, this, (TInt) ESchedLoop );
  1757 			return ESchedLoop;
  1758 			}
  1759 
  1760 		iStackSession->SetupCIMControl( aSessID );
  1761 		iWorkSet.Add( iStackSession );
  1762 		iStackSession->iState |= KMMCSessStateEngaged;
  1763 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDENQUESTACKSESSION_EXIT2, this, (TInt) ESchedContinue );
  1764 		return ESchedContinue;
  1765 	}
  1766 
  1767 void DMMCStack::SchedGrabEntries()
  1768 /**
  1769  * Merges Entry queue into Ready queue. Invoked at the scheduler entry and
  1770  * after the completion pass
  1771  */
  1772 	{
  1773 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDGRABENTRIES_ENTRY, this );
  1774 	
  1775 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sge"));
  1776 
  1777 	iAttention = EFalse;		// Strictly in this order
  1778 	if( !iEntryQueue.IsEmpty() )
  1779 		{
  1780 		DISABLEPREEMPTION
  1781 		iReadyQueue.Add( iEntryQueue );
  1782 		RESTOREPREEMPTION
  1783 		}
  1784 	OstTraceFunctionExit1( DMMCSTACK_SCHEDGRABENTRIES_EXIT, this );
  1785 	}
  1786 
  1787 void DMMCStack::SchedDisengage()
  1788 /**
  1789  * This function is called by AbortPass() and CompletionPass() to remove the session
  1790  * at WorkSet Point, to abort its asynchronous activities (if any) and
  1791  * clear up the dependent resources
  1792  */
  1793 	{
  1794 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDDISENGAGE_ENTRY, this );
  1795 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sd"));
  1796 
  1797 	DMMCSession* sessP = iWorkSet.Remove();
  1798 
  1799 	SchedDoAbort( sessP );
  1800 
  1801 	if( sessP == iSessionP )
  1802 		iSessionP = NULL;
  1803 
  1804 	if( sessP->iCardP != NULL && sessP->iCardP->iUsingSessionP == sessP )
  1805 		sessP->iCardP->iUsingSessionP = NULL;
  1806 
  1807 	// iAutoUnlockSession may attach to more than once card, so need to iterate 
  1808 	// through all cards and clear their session pointers if they match sessP
  1809 	if (sessP == &iAutoUnlockSession)
  1810 		{
  1811 		for (TUint i = 0; i < iMaxCardsInStack; i++)
  1812 			{
  1813 			TMMCard& cd = *(iCardArray->CardP(i));
  1814 			if (cd.iUsingSessionP == sessP)
  1815 				cd.iUsingSessionP = NULL;
  1816 			}
  1817 		}
  1818 
  1819 	if( sessP->iState & KMMCSessStateASSPEngaged )
  1820 		ASSPDisengage();
  1821 
  1822 	sessP->iState = 0;
  1823 	OstTraceFunctionExit1( DMMCSTACK_SCHEDDISENGAGE_EXIT, this );
  1824 	}
  1825 
  1826 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedAbortPass()
  1827 /**
  1828  * DMMCStack Scheduler private inline functions. These functions were separated as inline functions
  1829  * only for the sake of Scheduler() clarity.
  1830  */
  1831 	{
  1832 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDABORTPASS_ENTRY, this );
  1833 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sap"));
  1834 
  1835 	iAbortReq = EFalse;
  1836 	SchedGrabEntries();
  1837 	DMMCSession* sessP;
  1838 
  1839 	iWorkSet.Point();
  1840 
  1841 	while( (sessP = iWorkSet) != NULL )
  1842 		if( iAbortAll || sessP->iDoAbort )
  1843 			SchedDisengage();
  1844 		else
  1845 			iWorkSet++;
  1846 
  1847 	iReadyQueue.Point();
  1848 
  1849 	while( (sessP = iReadyQueue) != NULL )
  1850 		if( iAbortAll || sessP->iDoAbort )
  1851 			{
  1852 			iReadyQueue.Remove();
  1853 			sessP->iState = 0;
  1854 			}
  1855 		else
  1856 			iReadyQueue++;
  1857 
  1858 	if( iAbortReq )
  1859 	    {
  1860 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDABORTPASS_EXIT1, this, (TInt) ESchedLoop );
  1861 		return ESchedLoop;
  1862 	    }
  1863 
  1864 	// Clearing iAbortAll here is a bit dodgy. It wouldn't work if somebody interrupted us
  1865 	// at this point, enqued a session and then immediately called Reset() - that session
  1866 	// would not be discarded. However, the correct solution (enque Reset() requests
  1867 	// and process them in the Scheduler main loop) seems to be too expensive just to avoid
  1868 	// this particular effect.
  1869 	iAbortAll = EFalse;
  1870 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDABORTPASS_EXIT2, this, (TInt) ESchedContinue  );
  1871 	return ESchedContinue;
  1872 	}
  1873 
  1874 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedCompletionPass()
  1875 /**
  1876  * This function calls back all the sessions waiting to be completed
  1877  * Returns either Continue or Loop.
  1878  */
  1879 	{
  1880 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDCOMPLETIONPASS_ENTRY, this );
  1881 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:scp"));
  1882 
  1883 	iCompReq = EFalse;
  1884 	DMMCSession* sessP;
  1885 
  1886 	if( iCompleteAllExitCode )
  1887 		{
  1888 		SchedGrabEntries();
  1889 		iWorkSet.Add( iReadyQueue );
  1890 		}
  1891 
  1892 	iWorkSet.Point();
  1893 
  1894 	while( (sessP = iWorkSet) != NULL )
  1895 		if( iCompleteAllExitCode || sessP->iDoComplete )
  1896 			{
  1897 			if( (EffectiveModes(sessP->iConfig) & KMMCModeCompleteInStackDFC) != 0 &&
  1898 				 SchedGetOnDFC() )
  1899 				{
  1900 				// DFC has been queued so return back to main loop.  Next time
  1901 				// SchedGetOnDfc() will return EFalse, and the callback will be called.
  1902 				iCompReq = ETrue;
  1903 				OstTraceFunctionExitExt( DMMCSTACK_SCHEDCOMPLETIONPASS_EXIT1, this, (TInt) ESchedLoop );
  1904 				return ESchedLoop;
  1905 				}
  1906 
  1907 			SchedDisengage();					// calls iWorkSet.Remove
  1908 			sessP->iMMCExitCode |= iCompleteAllExitCode;
  1909 			// Update the controller store if a password operation was in progress.
  1910 			TBool doCallback = ETrue;
  1911 			if (sessP->iSessionID == ECIMLockUnlock)
  1912 				{
  1913 				iSocket->PasswordControlEnd(sessP, sessP->EpocErrorCode());
  1914 				
  1915 				if(sessP->EpocErrorCode() == KErrNone)
  1916 					{
  1917 					sessP->SetupCIMInitStackAfterUnlock();
  1918 					if(sessP->Engage() == KErrNone)
  1919 						{
  1920 						doCallback = EFalse;
  1921 						}
  1922 					}
  1923 				}
  1924 
  1925 			if(sessP->iSessionID == ECIMInitStackAfterUnlock)
  1926 				{
  1927 				// After unlocking the stack, cards may have switched into HS mode
  1928 				// (HS switch commands are only valid when the card is unlocked).
  1929 				//
  1930 				// Therefore, we need to re-negotiate the maximum bus clock again.
  1931 				//
  1932 				// The PSL will use this to set the master config (limiting the clock if
  1933 				// appropriate).
  1934 				//
  1935 				// Note that the clock may change when a specific card is selected.
  1936 				//
  1937 				TUint maxClk;
  1938 				iCardArray->UpdateAcquisitions(&maxClk);
  1939 				SetBusConfigDefaults( iMasterConfig.iBusConfig, maxClk );
  1940 				DoSetClock(maxClk);
  1941 				}
  1942 
  1943 			if(doCallback)
  1944 				{
  1945 				// call media driver completion routine or StackSessionCBST().
  1946 				sessP->iCallBack.CallBack();
  1947 				}
  1948 			}
  1949 		else
  1950 			iWorkSet++;
  1951 
  1952 	if( iCompReq )
  1953 	    {
  1954 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDCOMPLETIONPASS_EXIT2, this, (TInt) ESchedLoop );
  1955 		return ESchedLoop;
  1956 	    }
  1957 
  1958 	iCompleteAllExitCode = 0;
  1959 
  1960 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDCOMPLETIONPASS_EXIT3, this, ( TInt) ESchedContinue );
  1961 	return ESchedContinue;
  1962 	}
  1963 
  1964 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedInitStack()
  1965 /**
  1966  * "Immediate" InitStack initiator. Returns either Continue or Loop.
  1967  */
  1968 	{
  1969 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDINITSTACK_ENTRY, this );
  1970 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sis"));
  1971 
  1972 	if( SchedGetOnDFC() )
  1973 	    {
  1974 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDINITSTACK_EXIT1, this, (TInt) ESchedLoop );
  1975 		return ESchedLoop;
  1976 	    }
  1977 
  1978 	if( iSessionP != NULL && (iStackState & KMMCStackStateJobChooser) == 0 )
  1979 		{
  1980 		if( (iSessionP->iState & KMMCSessStateInProgress) )
  1981 			{
  1982 			if( SchedGroundDown(iSessionP, KMMCErrPowerDown) )
  1983 				{
  1984 				MarkComplete( iSessionP, KMMCErrPowerDown );
  1985 				OstTraceFunctionExitExt( DMMCSTACK_SCHEDINITSTACK_EXIT2, this, (TInt) ESchedLoop );
  1986 				return ESchedLoop;
  1987 				}
  1988 			}
  1989 		else
  1990 			iSessionP->iMachine.Reset();
  1991 		}
  1992 
  1993 	// NB if the current session was InitStack InProgress, JobChooser can not be active;
  1994 	// so we are not going to continue another InitStack as if nothing happened.
  1995 
  1996 	iStackState &= ~(KMMCStackStateInitInProgress|KMMCStackStateInitPending);
  1997 
  1998 	// If there is no current session (e.g. called from PowerUpStack()) or the current
  1999 	// session isn't specifically ECIMInitStack (which it rarely will be) then we have to use
  2000 	// the stack session to perform the stack init.
  2001 	if( iSessionP == NULL || iSessionP->iSessionID != ECIMInitStack )
  2002 		{
  2003 		if( SchedEnqueStackSession(ECIMInitStack) )
  2004 		    {
  2005 			OstTraceFunctionExitExt( DMMCSTACK_SCHEDINITSTACK_EXIT3, this, (TInt) ESchedLoop );
  2006 			return ESchedLoop;
  2007 		    }
  2008 
  2009 		SchedSetContext( iStackSession );	// make the internal session to be current job
  2010 		}
  2011 
  2012 	// Neither client nor internal session could be blocked here, not even on "BrokenLock"
  2013 	__ASSERT_ALWAYS( (iSessionP->iBlockOn)==0,
  2014 	DMMCSocket::Panic(DMMCSocket::EMMCInitStackBlocked) );
  2015 
  2016 	iStackState |= KMMCStackStateInitInProgress;
  2017 	// nothing can stop this session now; it's safe to clear iInitialise here.
  2018 	iInitialise = EFalse;
  2019 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDINITSTACK_EXIT4, this, (TInt) ESchedContinue );
  2020 	return ESchedContinue;
  2021 	}
  2022 
  2023 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedSleepStack()
  2024 /**
  2025  * "Immediate" Stack sleep mode. Returns either Continue or Loop.
  2026  */
  2027 	{
  2028 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDSLEEPSTACK_ENTRY, this );
  2029 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:SchdSlp!"));
  2030 
  2031 	// Make sure Stack DFC is Running!
  2032 	if( SchedGetOnDFC() )
  2033 		{
  2034 		__KTRACE_OPT(KPBUS1, Kern::Printf("mst:SchdSlp - DFC not running"));
  2035 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDSLEEPSTACK_EXIT1, this, (TInt) ESchedLoop );
  2036 		return ESchedLoop;
  2037 		}
  2038 
  2039 	if( iSessionP != NULL && (iStackState & KMMCStackStateJobChooser) == 0 )
  2040 		{
  2041 		if( (iSessionP->iState & KMMCSessStateInProgress) )
  2042 			{
  2043 			// A session has been queued before sleep, 
  2044 			// cancel sleep and loop for next session
  2045 			iSleep = EFalse;
  2046 			OstTraceFunctionExitExt( DMMCSTACK_SCHEDSLEEPSTACK_EXIT2, this, (TInt) ESchedLoop );
  2047 			return ESchedLoop;
  2048 			}
  2049 		}
  2050 	
  2051 	// Use the stack session to perform the stack sleep.
  2052 	if( SchedEnqueStackSession(ECIMSleep) )
  2053 		{
  2054 		__KTRACE_OPT(KPBUS1,Kern::Printf("SchdSlp: already Enqued"));
  2055 		// Stack already busy cancel sleep
  2056 		iSleep = EFalse;
  2057 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDSLEEPSTACK_EXIT3, this, (TInt) ESchedLoop );
  2058 		return ESchedLoop;
  2059 		}
  2060 
  2061 	SchedSetContext( iStackSession );	// make the internal session to be current job
  2062 
  2063 	// Sleep has now been queued
  2064 	iSleep = EFalse;
  2065 	iStackState |= KMMCStackStateSleepinProgress;
  2066 	__KTRACE_OPT(KPBUS1, Kern::Printf("<mst:SchdSlp"));
  2067 	
  2068 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDSLEEPSTACK_EXIT4, this, (TInt) ESchedLoop );
  2069 	return ESchedLoop;
  2070 	}
  2071 
  2072 
  2073 inline TBool DMMCStack::SchedPreemptable()
  2074 /**
  2075  * Checks if the current session can be preempted
  2076  */
  2077 	{	// strictly in the following order
  2078 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDPREEMPTABLE_ENTRY, this );
  2079 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:spe"));
  2080 	
  2081 	if( (iStackState & KMMCStackStateJobChooser) ||
  2082 		(iSessionP->iState & KMMCSessStateDoReSchedule) )
  2083 	    {
  2084 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT1, this, (TUint) ETrue );
  2085 		return ETrue;
  2086 	    }
  2087 
  2088 	if( (iSessionP->iBlockOn & KMMCBlockOnASSPFunction) )
  2089 	    {
  2090 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT2, this, (TUint) EFalse );
  2091 		return EFalse;
  2092 	    }
  2093 
  2094 	TBool preemptDC = EFalse;	
  2095 
  2096 	if (iSessionP->iBlockOn & KMMCBlockOnYielding)
  2097 		{
  2098 		// Added to support yielding the stack for a specific command.
  2099 		preemptDC = ETrue;		
  2100 		}
  2101 	else if( (iSessionP->iBlockOn & KMMCBlockOnDataTransfer) )
  2102 		{
  2103 		// Added for SDIO Read/Wait and SDC support.  This condition
  2104 		// is set at the variant, and determines whether commands may be
  2105 		// issued during the data transfer period.
  2106 		if(!(iSessionP->iState & KMMCSessStateAllowDirectCommands))
  2107 		    {
  2108 			OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT3, this, (TUint) EFalse );
  2109 			return EFalse;
  2110 		    }
  2111 		
  2112 		// We must consider the remaining blocking conditions
  2113 		// before being sure that we can enable pre-emtion of this session
  2114 		preemptDC = ETrue;
  2115 		}
  2116 
  2117 	if( (iSessionP->iBlockOn & (KMMCBlockOnCardInUse | KMMCBlockOnNoRun)) )
  2118 	    {
  2119 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT4, this, (TUint) ETrue );
  2120 		return ETrue;
  2121 	    }
  2122 	
  2123 	if( (iConfig.iModes & KMMCModeEnablePreemption) == 0 )
  2124 	    {
  2125 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT5, this, (TUint) EFalse );
  2126 		return EFalse;
  2127 	    }
  2128 
  2129 	if( (iSessionP->iBlockOn & KMMCBlockOnGapTimersMask) &&
  2130 		(iConfig.iModes & KMMCModePreemptInGaps) &&
  2131 		(iSessionP->iState & KMMCSessStateSafeInGaps) )
  2132 	    {
  2133 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT6, this, (TUint) ETrue );
  2134 		return ETrue;
  2135 	    }
  2136 
  2137 	if( iSessionP->iBlockOn & KMMCBlockOnInterrupt )
  2138 	    {
  2139 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT7, this, (TUint) ETrue );
  2140 		return ETrue;
  2141 	    }
  2142 
  2143 	if(preemptDC)
  2144 	    {
  2145 		OstTraceFunctionExitExt( DDMMCSTACK_SCHEDPREEMPTABLE_EXIT8, this, (TUint) ETrue );
  2146 		return ETrue;
  2147 	    }
  2148 		
  2149 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT9, this, (TUint) EFalse );
  2150 	return EFalse;
  2151 	}
  2152 
  2153 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedSession()
  2154 /**
  2155  * Current context analyser. Returns Exit, Loop or ChooseJob.
  2156  */
  2157 	{
  2158 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDSESSION_ENTRY, this );
  2159 
  2160 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ss"));
  2161 
  2162 	// If no current session selected then we need to choose one
  2163 	if (iSessionP == NULL)
  2164 	    {
  2165 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT1, this, (TInt) ESchedChooseJob );
  2166 		return ESchedChooseJob;
  2167 	    }
  2168 
  2169 	// Check any static blocking conditions on the current session and remove if possible
  2170 	if (SchedResolveStatBlocks(iSessionP)==ESchedLoop)
  2171 	    {
  2172 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT2, this, (TInt) ESchedLoop );
  2173 		return ESchedLoop;
  2174 	    }
  2175 
  2176 	// If current session is still blocked, see if we could pre-empt the session
  2177 	if (iSessionP->iBlockOn)
  2178 		{
  2179 		if( SchedPreemptable() )
  2180 		    {
  2181 		    OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT3, this, (TInt) ESchedChooseJob );
  2182 			return ESchedChooseJob;
  2183 		    }
  2184 
  2185 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT4, this, (TInt) ESchedExit );
  2186 		return ESchedExit;	// No preemption possible
  2187 		}
  2188 
  2189 	// If the current session has been marked to be 'un-scheduled' then we
  2190 	// need to choose another session if ones available
  2191 	if ( (iSessionP->iState & KMMCSessStateDoReSchedule) )
  2192 	    {
  2193 		OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT5, this, (TInt) ESchedChooseJob );
  2194 		return ESchedChooseJob;
  2195 	    }
  2196 
  2197 	// Check if this session requires to be run in DFC context - loop if necessary
  2198 	if ( (iSessionP->iState & KMMCSessStateDoDFC) )
  2199 		{
  2200 		iSessionP->iState &= ~KMMCSessStateDoDFC;
  2201 		if( SchedGetOnDFC()==ESchedLoop )
  2202 		    {
  2203 			OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT6, this, (TInt) ESchedLoop );
  2204 			return ESchedLoop;
  2205 		    }
  2206 		}
  2207 
  2208 	// Now we actually execute the current session
  2209 	if( iLockingSessionP != NULL )
  2210 		{
  2211 		if( (iStackState & KMMCStackStateLocked) )
  2212 			{
  2213 			if( iSessionP != iLockingSessionP )
  2214 				{
  2215 				iLockingSessionP->iBrokenLock = ETrue;
  2216 				iLockingSessionP = NULL;
  2217 				DeselectsToIssue(KMMCIdleCommandsAtRestart); // use it for the number of deselects as well
  2218 				}
  2219 			}
  2220 		else
  2221 			if( iSessionP == iLockingSessionP )
  2222 				iStackState |= KMMCStackStateLocked;
  2223 		}
  2224 
  2225 	if( iSessionP->iInitContext != iInitContext )
  2226 		{
  2227 		// If the current session's init_stack pass number is set but isn't the same as the current
  2228 		// pass number, it indicates this session is being resumed having tried to recover from
  2229 		// a bus inconsitency by re-initialising the stack. Set the exit code to a special
  2230 		// value so this session can un-wind from where the initial error occured, back to the start.
  2231 		if( iSessionP->iInitContext != 0 )
  2232 			//coverity[check_return]
  2233 			//return value is not saved or checked because there is no further uses.
  2234 			iSessionP->iMachine.SetExitCode(KMMCErrInitContext | iSessionP->iMachine.ExitCode());
  2235 
  2236 		iSessionP->iInitContext = iInitContext;
  2237 		}
  2238 
  2239 	iStackState &= ~KMMCStackStateJobChooser;
  2240 	iSessionP->iState &= ~KMMCSessStateSafeInGaps;
  2241 
  2242 	// Execute the session state machine until it completes, is blocked or is aborted.
  2243 	TMMCErr exitCode = iSessionP->iMachine.Dispatch();
  2244 
  2245 	iStackState &= ~KMMCStackStateReScheduled;
  2246 
  2247 	if( exitCode )
  2248 		MarkComplete( iSessionP, (exitCode & ~KMMCErrBypass) );
  2249 
  2250 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT7, this, (TInt) ESchedLoop );
  2251 	return ESchedLoop;
  2252 	}
  2253 
  2254 TBool DMMCStack::SchedYielding(DMMCSession* aSessP)
  2255 /**
  2256  * Check whether the scheduler should yield to another command
  2257  */
  2258 	{
  2259 	OstTraceFunctionEntryExt( DMMCSTACK_SCHEDYIELDING_ENTRY, this );
  2260 	// Test whether a full loop through the sessions has occurred during a yield
  2261 	if ((aSessP->iBlockOn & KMMCBlockOnYielding) && (iStackState & KMMCStackStateYielding))
  2262 		{
  2263 		// We've looped, now stop yielding
  2264 		aSessP->iBlockOn &= ~KMMCBlockOnYielding;
  2265 		iStackState &= ~KMMCStackStateYielding;
  2266 		}
  2267 	TBool ret = (iStackState & KMMCStackStateYielding) != 0;
  2268 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDYIELDING_EXIT, this, ret );
  2269 	return ret;
  2270 	}
  2271 
  2272 TBool DMMCStack::SchedAllowDirectCommands(DMMCSession* aSessP)
  2273 /**
  2274  * Check whether direct only commands can be run.
  2275  */
  2276 	{
  2277 	OstTraceFunctionEntryExt( DMMCSTACK_SCHEDALLOWDIRECTCOMMANDS_ENTRY, this );
  2278 	TBool allowDirectCommands = EFalse;
  2279 
  2280 	// Test the remaining sessions to see if they have a DMA data transfer blockage which allow direct commands only
  2281 	DMMCSession* testSessP = aSessP;
  2282 	do
  2283 		{
  2284 		if ((testSessP->iBlockOn & KMMCBlockOnDataTransfer) && (testSessP->iState & KMMCSessStateAllowDirectCommands))
  2285 			allowDirectCommands = ETrue;
  2286 		testSessP = testSessP->iLinkP;
  2287 		}			
  2288 	while((aSessP != testSessP) && (testSessP != NULL));
  2289 
  2290 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDALLOWDIRECTCOMMANDS_EXIT, this, allowDirectCommands );
  2291 	return allowDirectCommands;
  2292 	}
  2293 
  2294 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedChooseJob()
  2295 /**
  2296  * Find an unblocked job to run. Returns Exit or Loop.
  2297  */
  2298 	{
  2299 	OstTraceFunctionEntry1( DMMCSTACK_SCHEDCHOOSEJOB_ENTRY, this );
  2300 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:scj"));
  2301 
  2302 	iStackState |= KMMCStackStateJobChooser;
  2303 	SchedGrabEntries();
  2304 	DMMCSession* sessP = NULL;
  2305 
  2306 	if( iLockingSessionP != NULL )		// if stack is already locked we accept only locking session
  2307 		{
  2308 		if( iWorkSet.IsEmpty() && iReadyQueue.Point(iLockingSessionP) )
  2309 			sessP = iReadyQueue.Remove();
  2310 		}
  2311 	else								// otherwise we might add a fresh session from reserve
  2312 		{
  2313 		iStackState &= ~KMMCStackStateLocked;
  2314 		if( iWorkSet.Size() < KMMCMaxJobsInStackWorkSet &&		// if work set is not too big
  2315 			!iReadyQueue.IsEmpty() &&							// and there are ready sessions
  2316 			(iStackState & KMMCStackStateWaitingToLock) == 0 )	// and nobody waits to lock us
  2317 			{
  2318 			iReadyQueue.Point();								// at marker to preserve FIFO
  2319 			sessP = iReadyQueue.Remove();
  2320 			}
  2321 		}
  2322 
  2323 	if( sessP != NULL )
  2324 		{
  2325 		iWorkSet.Add( sessP );
  2326 
  2327 		if( sessP->iSessionID == ECIMLockStack )
  2328 			{
  2329 			sessP->SynchBlock( KMMCBlockOnWaitToLock | KMMCBlockOnNoRun );
  2330 			sessP->iBrokenLock = EFalse;
  2331 			iStackState |= KMMCStackStateWaitingToLock;
  2332 			}
  2333 		}
  2334 	
  2335 	if( iSessionP  != NULL )
  2336 		iWorkSet.AdvanceMarker();		// move current session to the end of the queue
  2337 
  2338 	iWorkSet.Point();
  2339 	
  2340 	while( (sessP = iWorkSet) != NULL )
  2341 		{
  2342 		// first, remove all static blocking conditions
  2343 		if( SchedResolveStatBlocks(sessP) )
  2344 		    {
  2345 			OstTraceFunctionExitExt( DMMCSTACK_SCHEDCHOOSEJOB_EXIT1, this, (TInt) ESchedLoop );
  2346 			return ESchedLoop;
  2347 		    }
  2348 
  2349 		TBool scheduleSession = ETrue;
  2350 		// Test whether we are yielding 
  2351 		if (SchedYielding(sessP) && (sessP->Command().iSpec.iCommandType != iYieldCommandType))
  2352 			scheduleSession = EFalse;
  2353 		// Test whether this session is blocked
  2354 		else if (sessP->iBlockOn)
  2355 			scheduleSession = EFalse;
  2356 		// Test whether we can only handle direct commands
  2357 		else if (SchedAllowDirectCommands(sessP) && (sessP->Command().iSpec.iCommandType != ECmdTypeADC))
  2358 			scheduleSession = EFalse;
  2359 		
  2360 		if (scheduleSession)
  2361 			{
  2362 			iWorkSet.SetMarker();
  2363 			SchedSetContext( sessP );
  2364 			OstTraceFunctionExitExt( DMMCSTACK_SCHEDCHOOSEJOB_EXIT2, this, (TInt) ESchedLoop );
  2365 			return ESchedLoop;
  2366 			}
  2367 			
  2368 		iWorkSet++;
  2369 		}
  2370 	
  2371 	OstTraceFunctionExitExt( DMMCSTACK_SCHEDCHOOSEJOB_EXIT3, this, (TInt) ESchedExit );
  2372 	return ESchedExit;		
  2373 	}
  2374 
  2375 void DMMCStack::StackDFC(TAny* aStackP)
  2376 /**
  2377  * This DFC is used to startup Stack Scheduler from the background.
  2378  */
  2379 	{
  2380 	OstTraceFunctionEntry0( DMMCSTACK_STACKDFC_ENTRY );
  2381 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sdf"));
  2382 
  2383 	DMMCStack* const stackP = static_cast<DMMCStack*>(aStackP);
  2384 	stackP->Scheduler( stackP->iDFCRunning );
  2385 	OstTraceFunctionExit0( DMMCSTACK_STACKDFC_EXIT );
  2386 	}
  2387 
  2388 void DMMCStack::Scheduler(volatile TBool& aFlag)
  2389 /**
  2390  * This is the main function which controls, monitors and synchronises session execution.
  2391  * It's divided into the entry function Scheduler() and the scheduling mechanism itself,
  2392  * DoSchedule()
  2393  */
  2394 	{
  2395 	OstTraceFunctionEntry0( DMMCSTACK_SCHEDULER_ENTRY );
  2396 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sch"));
  2397 
  2398 	DISABLEPREEMPTION
  2399 	aFlag = ETrue;
  2400 
  2401 	if( iStackState & KMMCStackStateRunning )
  2402 		{
  2403 		RESTOREPREEMPTION
  2404 		return;
  2405 		}
  2406 
  2407 	iStackState |= KMMCStackStateRunning;
  2408 	RESTOREPREEMPTION
  2409 	DoSchedule();
  2410 	OstTraceFunctionExit0( DMMCSTACK_SCHEDULER_EXIT );
  2411 	}
  2412 
  2413 void DMMCStack::DoSchedule()
  2414 	{
  2415 	OstTraceFunctionEntry1( DMMCSTACK_DOSCHEDULE_ENTRY, this );
  2416 	__KTRACE_OPT(KPBUS1,Kern::Printf(">mst:dos"));
  2417 
  2418 	for(;;)
  2419 		{
  2420 		for(;;)
  2421 			{
  2422 			if( iAbortReq && SchedAbortPass() )
  2423 				continue;
  2424 
  2425 			if( iDFCRunning )
  2426 				iStackState &= ~KMMCStackStateWaitingDFC;
  2427 			else
  2428 				if( iStackState & KMMCStackStateWaitingDFC )
  2429 					break;
  2430 
  2431 			if( iCompReq && SchedCompletionPass() )
  2432 				continue;
  2433 
  2434 			if( iInitialise && SchedInitStack() )
  2435 				continue;
  2436 						
  2437 			if( iSleep && SchedSleepStack() )
  2438 				continue;
  2439 
  2440 			iAttention = EFalse;
  2441 
  2442 			DMMCStack::TMMCStackSchedStateEnum toDo = SchedSession();
  2443 
  2444 			if( toDo == ESchedLoop )
  2445 				continue;
  2446 
  2447 			if( toDo == ESchedExit )
  2448 				break;
  2449 
  2450 			if( SchedChooseJob() == ESchedExit )
  2451 				break;
  2452 			}
  2453 
  2454 		DISABLEPREEMPTION
  2455 
  2456 		if( !iAbortReq &&
  2457 			((iStackState & KMMCStackStateWaitingDFC) ||
  2458 			 (iCompReq | iInitialise | iAttention)==0) ||
  2459 			 ((iSessionP) && (iSessionP->iState & KMMCSessStateAllowDirectCommands)))
  2460 			{
  2461 			// Clear DFC flag here in case somebody was running scheduler in the background
  2462 			// when DFC turned up. This should never really happen, but with EPOC who knows
  2463 			iStackState &= ~KMMCStackStateRunning;
  2464 			iDFCRunning = EFalse;
  2465 			
  2466 			RESTOREPREEMPTION
  2467 			__KTRACE_OPT(KPBUS1,Kern::Printf("<mst:dos"));
  2468 			OstTraceFunctionExit1( DMMCSTACK_DOSCHEDULE_EXIT1, this );
  2469 			return;
  2470 			}
  2471 
  2472 		RESTOREPREEMPTION
  2473 		}
  2474 	}
  2475 
  2476 //
  2477 // DMMCStack:: --- Session service ---
  2478 //
  2479 void DMMCStack::Add(DMMCSession* aSessP)
  2480 /**
  2481  * Adds session aSessP to the EntryQueue (asynchronous function)
  2482  */
  2483 	{
  2484 	OstTraceFunctionEntryExt( DMMCSTACK_ADD_ENTRY, this );
  2485 	ASSERT_NOT_ISR_CONTEXT
  2486 	__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Add %d",TUint(aSessP->iSessionID)));
  2487 
  2488 	DISABLEPREEMPTION
  2489 	iEntryQueue.Add( aSessP );
  2490 	aSessP->iState |= KMMCSessStateEngaged;
  2491 	RESTOREPREEMPTION
  2492 	Scheduler( iAttention );
  2493 	OstTraceFunctionExit1( DMMCSTACK_ADD_EXIT, this );
  2494 	}
  2495 
  2496 void DMMCStack::Abort(DMMCSession* aSessP)
  2497 /**
  2498  * Aborts a session
  2499  */
  2500 	{
  2501 	OstTraceFunctionEntryExt( DMMCSTACK_ABORT_ENTRY, this );
  2502 	ASSERT_NOT_ISR_CONTEXT
  2503 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:abt"));
  2504 
  2505 	if( !aSessP->IsEngaged() )
  2506 	    {
  2507 		OstTraceFunctionExit1( DMMCSTACK_ABORT_EXIT1, this );
  2508 		return;
  2509 	    }
  2510 
  2511 	aSessP->iDoAbort = ETrue;
  2512 	aSessP->iMachine.Abort();
  2513 
  2514 	Scheduler( iAbortReq );
  2515 	OstTraceFunctionExit1( DMMCSTACK_ABORT_EXIT2, this );
  2516 	}
  2517 
  2518 void DMMCStack::Stop(DMMCSession* aSessP)
  2519 /**
  2520  * Signals session to stop
  2521  */
  2522 	{
  2523 	OstTraceFunctionEntryExt( DMMCSTACK_STOP1_ENTRY, this );
  2524 	ASSERT_NOT_ISR_CONTEXT
  2525 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:stp"));
  2526 
  2527 	if( !aSessP->IsEngaged() )
  2528 	    {
  2529 		OstTraceFunctionExit1( DMMCSTACK_STOP1_EXIT1, this );
  2530 		return;
  2531 	    }
  2532 
  2533 	aSessP->iDoStop = ETrue;
  2534 	OstTraceFunctionExit1( DMMCSTACK_STOP1_EXIT2, this );
  2535 	}
  2536 
  2537 EXPORT_C void DMMCStack::Block(DMMCSession* aSessP, TUint32 aFlag)
  2538 	{
  2539 	OstTraceFunctionEntryExt( DMMCSTACK_BLOCK_ENTRY, this );
  2540 	ASSERT_NOT_ISR_CONTEXT
  2541 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:blk"));
  2542 
  2543 	if( !aSessP->IsEngaged() )
  2544 	    {
  2545 		OstTraceFunctionExit1( DMMCSTACK_BLOCK_EXIT1, this );
  2546 		return;
  2547 	    }
  2548 
  2549 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:blk:[aFlag=%08x, iBlockOn=%08x]", aFlag, aSessP->iBlockOn));
  2550 	OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_BLOCK, "aFlag=0x%08x; iBlockOn=0x%08x", aFlag, aSessP->iBlockOn );
  2551 	
  2552 
  2553 	(void)__e32_atomic_ior_ord32(&aSessP->iBlockOn, aFlag);
  2554 	OstTraceFunctionExit1( DMMCSTACK_BLOCK_EXIT2, this );
  2555 	}
  2556 
  2557 EXPORT_C void DMMCStack::UnBlock(DMMCSession* aSessP, TUint32 aFlag, TMMCErr anExitCode)
  2558 /**
  2559  * aFlag is a bitset of KMMCBlockOnXXX events that have occured.  If the stack's
  2560  * session is waiting on all of these events, then it is scheduled.
  2561  */
  2562 	{
  2563 	OstTraceExt4(TRACE_FLOW, DMMCSTACK_UNBLOCK_ENTRY , "DMMCStack::UnBlock;aSessP=%x;aFlag=%x;anExitCode=%d;this=%x", (TUint) aSessP, (TUint) aFlag, (TInt) anExitCode, (TUint) this);
  2564 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ubl"));
  2565 
  2566 	if (aSessP != NULL)
  2567 		{
  2568 		__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ubl:[aFlag=%08x, iBlockOn=%08x", aFlag, aSessP->iBlockOn));
  2569 		OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_UNBLOCK, "aFlag=0x%08x; iBlockOn=0x%08x", aFlag, aSessP->iBlockOn );
  2570 		
  2571 
  2572 		if( (aSessP->iBlockOn & aFlag) == 0 )
  2573 		    {
  2574 			OstTraceFunctionExit1( DMMCSTACK_UNBLOCK_EXIT1, this );
  2575 			return;
  2576 		    }
  2577 
  2578 		// Must be either in a DFC or have the KMMCSessStateDoDFC flag set
  2579 		__ASSERT_DEBUG( 
  2580 			(aSessP->iState & KMMCSessStateDoDFC) != 0 || 
  2581 			NKern::CurrentContext() != NKern::EInterrupt,
  2582 			DMMCSocket::Panic(DMMCSocket::EMMCUnblockingInWrongContext));
  2583 
  2584 		(void)__e32_atomic_and_ord32(&aSessP->iBlockOn, ~aFlag);
  2585 		aSessP->iMachine.SetExitCode( anExitCode );
  2586 
  2587 		if( aSessP->iBlockOn == 0 )
  2588 			Scheduler( iAttention );
  2589 		}
  2590 	OstTraceFunctionExit1( DMMCSTACK_UNBLOCK_EXIT2, this );
  2591 	}
  2592 
  2593 void DMMCStack::UnlockStack(DMMCSession* aSessP)
  2594 /**
  2595  * Removes stack lock. Asynchronous function.
  2596  */
  2597 	{
  2598 	OstTraceFunctionEntryExt( DMMCSTACK_UNLOCKSTACK_ENTRY, this );
  2599 	ASSERT_NOT_ISR_CONTEXT
  2600 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ust"));
  2601 
  2602 	aSessP->iBrokenLock = EFalse;
  2603 
  2604 	if( aSessP == iLockingSessionP )
  2605 		{
  2606 		iLockingSessionP = NULL;
  2607 		Scheduler( iAttention );
  2608 		}
  2609 	OstTraceFunctionExit1( DMMCSTACK_UNLOCKSTACK_EXIT1, this );
  2610 	}
  2611 
  2612 EXPORT_C TInt DMMCStack::Stop(TMMCard* aCardP)
  2613 /**
  2614  * Completes all sessions operating with a specified card with KMMCErrAbort.
  2615  * Returns either KErrNone or KErrServerBusy.
  2616  */
  2617 	{
  2618 	OstTraceFunctionEntryExt( DMMCSTACK_STOP2_ENTRY, this );
  2619 	ASSERT_NOT_ISR_CONTEXT
  2620 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:stp"));
  2621 
  2622 	DISABLEPREEMPTION
  2623 
  2624 	if( iStackState & KMMCStackStateRunning )
  2625 		{
  2626 		RESTOREPREEMPTION
  2627 		return KErrServerBusy;	// can not operate in foreground
  2628 		}
  2629 
  2630 	iStackState |= KMMCStackStateRunning;
  2631 	RESTOREPREEMPTION
  2632 
  2633 	DMMCSession* sessP;
  2634 	SchedGrabEntries();
  2635 
  2636 	iWorkSet.Point();
  2637 
  2638 	while( (sessP = iWorkSet++) != NULL )
  2639 		if( sessP->iCardP == aCardP )
  2640 			MarkComplete( sessP, KMMCErrAbort );
  2641 
  2642 	iReadyQueue.Point();
  2643 
  2644 	while( (sessP = iReadyQueue) != NULL )
  2645 		if( sessP->iCardP == aCardP )
  2646 			{
  2647 			MarkComplete( sessP, KMMCErrAbort );
  2648 			iReadyQueue.Remove();
  2649 			iWorkSet.Add( sessP );
  2650 			}
  2651 		else
  2652 			iReadyQueue++;
  2653 
  2654 	SchedGetOnDFC();
  2655 	DoSchedule();
  2656 	OstTraceFunctionExitExt( DMMCSTACK_STOP2_EXIT, this, KErrNone );
  2657 	return KErrNone;
  2658 	}
  2659 
  2660 void DMMCStack::MarkComplete(DMMCSession* aSessP, TMMCErr anExitCode)
  2661 /**
  2662  * Marks session to be completed on the next scheduler pass.
  2663  */
  2664 	{
  2665 	OstTraceExt3(TRACE_FLOW, DMMCSTACK_MARKCOMPLETE_ENTRY ,"DMMCStack::MarkComplete;aSessP=%x;anExitCode=%d;this=%x", (TUint) aSessP, (TInt) anExitCode, (TUint) this);
  2666 	ASSERT_NOT_ISR_CONTEXT
  2667 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:mcp"));
  2668 
  2669 	aSessP->SynchBlock( KMMCBlockOnNoRun );
  2670 	aSessP->iMMCExitCode = anExitCode;
  2671 	aSessP->iDoComplete = ETrue;
  2672 	iCompReq = ETrue;
  2673 	OstTraceFunctionExit1( DMMCSTACK_MARKCOMPLETE_EXIT, this );
  2674 	}
  2675 
  2676 //
  2677 // DMMCStack:: --- Miscellaneous ---
  2678 //
  2679 EXPORT_C TUint32 DMMCStack::EffectiveModes(const TMMCStackConfig& aClientConfig)
  2680 /**
  2681  * Calculates effective client modes as real client modes merged with iMasterConfig modes
  2682  */
  2683 	{
  2684 	OstTraceFunctionEntry1( DMMCSTACK_EFFECTIVEMODES_ENTRY, this );
  2685 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:em"));
  2686 
  2687 	const TUint32 masterMode = (iMasterConfig.iModes & iMasterConfig.iUpdateMask) |
  2688 								(KMMCModeDefault & ~iMasterConfig.iUpdateMask);
  2689 
  2690 	const TUint32 c = aClientConfig.iClientMask;
  2691 	const TUint32 u = aClientConfig.iUpdateMask;
  2692 	const TUint32 m = aClientConfig.iModes;
  2693 	const TUint32 userMode = (c & ((m & u) | ~u)) | (m & KMMCModeMask);
  2694 	const TUint32 userMask = (u | KMMCModeClientMask) &
  2695 							((masterMode & KMMCModeMasterOverrides) | ~KMMCModeMasterOverrides);
  2696 
  2697 	const TUint32 effectiveMode = (userMode & userMask) | (masterMode & ~userMask);
  2698 
  2699 	if( effectiveMode & KMMCModeEnableClientConfig )
  2700 	    {
  2701 		OstTraceFunctionExitExt( DMMCSTACK_EFFECTIVEMODES_EXIT1, this, ( TUint )( effectiveMode ) );
  2702 		return effectiveMode;
  2703 	    }
  2704 	else
  2705 	    {
  2706 	    
  2707 		TUint32 ret = (effectiveMode & KMMCModeClientOverrides) |
  2708 				(masterMode & ~(KMMCModeClientOverrides | KMMCModeClientMask));
  2709 		OstTraceFunctionExitExt( DMMCSTACK_EFFECTIVEMODES_EXIT2, this, ( TUint )( ret ) );
  2710 		return ret;
  2711 	    }
  2712 	}
  2713 
  2714 void DMMCStack::MergeConfig(DMMCSession* aSessP)
  2715 /**
  2716  * Merges client and master configuration into iConfig
  2717  */
  2718 	{
  2719 	OstTraceFunctionEntryExt( DMMCSTACK_MERGECONFIG_ENTRY, this );
  2720 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:mc"));
  2721 
  2722 	TMMCStackConfig& cC = aSessP->iConfig;
  2723 	TMMCStackConfig& mC = iMasterConfig;
  2724 	const TUint32 modes = EffectiveModes( cC );
  2725 	const TUint32 mastM = mC.iClientMask;
  2726 
  2727 	iConfig.iModes = modes;
  2728 
  2729 	iConfig.iPollAttempts =
  2730 			(modes & KMMCModeClientPollAttempts)
  2731 		?	cC.iPollAttempts
  2732 		:	((mastM & KMMCModeClientPollAttempts) ? mC.iPollAttempts : KMMCMaxPollAttempts);
  2733 
  2734 	iConfig.iTimeOutRetries =
  2735 			(modes & KMMCModeClientTimeOutRetries)
  2736 		?	cC.iTimeOutRetries
  2737 		:	((mastM & KMMCModeClientTimeOutRetries) ? mC.iTimeOutRetries : KMMCMaxTimeOutRetries);
  2738 
  2739 	iConfig.iCRCRetries =
  2740 			(modes & KMMCModeClientCRCRetries)
  2741 		?	cC.iCRCRetries
  2742 		:	((mastM & KMMCModeClientCRCRetries) ? mC.iCRCRetries : KMMCMaxCRCRetries);
  2743 
  2744 	iConfig.iUnlockRetries =
  2745 			(modes & KMMCModeClientUnlockRetries)
  2746 		?	cC.iUnlockRetries
  2747 		:	((mastM & KMMCModeClientUnlockRetries) ? mC.iUnlockRetries : KMMCMaxUnlockRetries);
  2748 		
  2749 	iConfig.iOpCondBusyTimeout =
  2750 			(modes & KMMCModeClientiOpCondBusyTimeout)
  2751 		?	cC.iOpCondBusyTimeout
  2752 		:	((mastM & KMMCModeClientiOpCondBusyTimeout) ? mC.iOpCondBusyTimeout : KMMCMaxOpCondBusyTimeout);	
  2753 
  2754 	// There are no default constants defining BusConfig parameters.
  2755 	// iMasterConfig.iBusConfig must be initialised by ASSP layer
  2756 
  2757 	// _?_? The code below can be modified later for a card controlled session
  2758 	// to include CSD analisys and calculate time-out and clock parameters on that basis.
  2759 	// As it written now, the defaults for all cards will be the same.
  2760 
  2761 	if( modes & KMMCModeClientBusClock )
  2762 		{
  2763 		TUint clock = cC.iBusConfig.iBusClock;
  2764 		if( clock > mC.iBusConfig.iBusClock )
  2765 			clock = mC.iBusConfig.iBusClock;
  2766 		if( clock < KMMCBusClockFOD )
  2767 			clock = KMMCBusClockFOD;
  2768 		DoSetClock(clock);
  2769 		}
  2770 	else if( modes & KMMCModeCardControlled && aSessP->CardP() )
  2771 		{
  2772 		TUint clock = MaxTranSpeedInKilohertz(*aSessP->CardP());
  2773 		if( clock > mC.iBusConfig.iBusClock )
  2774 			clock = mC.iBusConfig.iBusClock;
  2775 		if( clock < KMMCBusClockFOD )
  2776 			clock = KMMCBusClockFOD;
  2777 		DoSetClock(clock);
  2778 		}
  2779 	else
  2780 		DoSetClock(mC.iBusConfig.iBusClock);
  2781 
  2782 	iConfig.iBusConfig.iClockIn = (modes & KMMCModeClientClockIn)
  2783 							? cC.iBusConfig.iClockIn
  2784 							: mC.iBusConfig.iClockIn;
  2785 
  2786 	iConfig.iBusConfig.iClockOut = (modes & KMMCModeClientClockOut)
  2787 							? cC.iBusConfig.iClockOut
  2788 							: mC.iBusConfig.iClockOut;
  2789 
  2790 	iConfig.iBusConfig.iResponseTimeOut = (modes & KMMCModeClientResponseTimeOut)
  2791 							? cC.iBusConfig.iResponseTimeOut
  2792 							: mC.iBusConfig.iResponseTimeOut;
  2793 
  2794 	iConfig.iBusConfig.iDataTimeOut = (modes & KMMCModeClientDataTimeOut)
  2795 							? cC.iBusConfig.iDataTimeOut
  2796 							: mC.iBusConfig.iDataTimeOut;
  2797 
  2798 	iConfig.iBusConfig.iBusyTimeOut = (modes & KMMCModeClientBusyTimeOut)
  2799 							? cC.iBusConfig.iBusyTimeOut
  2800 							: mC.iBusConfig.iBusyTimeOut;
  2801 	OstTraceFunctionExit1( DMMCSTACK_MERGECONFIG_EXIT, this );
  2802 	}
  2803 
  2804 TBool DMMCStack::StaticBlocks()
  2805 /**
  2806  * This function realises the potential blocking conditions of the current session.
  2807  * Returns ETrue if the session has to be stopped right now
  2808  */
  2809 	{
  2810 	OstTraceFunctionEntry1( DMMCSTACK_STATICBLOCKS_ENTRY, this );
  2811 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:stb"));
  2812 
  2813 	if( iSessionP->iDoStop )
  2814 		{
  2815 		MarkComplete( iSessionP, KMMCErrAbort );
  2816 		OstTraceFunctionExitExt( DMMCSTACK_STATICBLOCKS_EXIT1, this, (TUint) ETrue );
  2817 		return ETrue;
  2818 		}
  2819 
  2820 	if( !iDFCRunning && (iSessionP->iState & KMMCSessStateDoDFC) )
  2821 	    {
  2822 		OstTraceFunctionExitExt( DMMCSTACK_STATICBLOCKS_EXIT2, this, (TUint) ETrue );
  2823 		return ETrue;
  2824 	    }
  2825 
  2826 	TBool ret = (iSessionP->iState & KMMCSessStateDoReSchedule) != 0; 
  2827 	OstTraceFunctionExitExt( DMMCSTACK_STATICBLOCKS_EXIT3, this, ret );
  2828 	return ret;
  2829 	}
  2830 
  2831 
  2832 EXPORT_C TBool DMMCStack::CardDetect(TUint /*aCardNumber*/)
  2833 /**
  2834  * Returns ETrue when a card is present in the card socket 'aCardNumber'.
  2835  * Default implementation when not provided by ASSP layer.
  2836  */
  2837 	{
  2838 	return(ETrue);
  2839 	}
  2840 
  2841 EXPORT_C TBool DMMCStack::WriteProtected(TUint /*aCardNumber*/)
  2842 /**
  2843  * Returns ETrue when the card in socket 'aCardNumber' is mechanically write
  2844  * protected.
  2845  * Default implementation when not provided by ASSP layer.
  2846  */
  2847 	{
  2848 	return(EFalse);
  2849 	}
  2850 
  2851 //	--------  DMMCStack State Machine functions  --------
  2852 //
  2853 
  2854 // Auxiliary SM function service
  2855 
  2856 void DMMCStack::StackSessionCBST(TAny* aStackP)
  2857 /**
  2858  * Stack Session completion routine.
  2859  */
  2860 	{
  2861 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sscbs"));
  2862 	static_cast<DMMCStack *>(aStackP)->StackSessionCB();
  2863 	}
  2864 
  2865 
  2866 TInt DMMCStack::StackSessionCB()
  2867 	{
  2868 	OstTraceFunctionEntry1( DMMCSTACK_STACKSESSIONCB_ENTRY, this );
  2869 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sscb "));
  2870 
  2871 	if (iStackState & KMMCStackStateSleepinProgress)
  2872 		{
  2873 		// Sleep completed update stack state
  2874 		iStackState &= ~KMMCStackStateSleepinProgress;
  2875 		OstTraceFunctionExit1( DMMCSTACK_STACKSESSIONCB_EXIT1, this );
  2876 		return 0;
  2877 		}
  2878 	
  2879 	TMMCErr mmcError = iStackSession->MMCExitCode();
  2880 	iStackState &= ~KMMCStackStateInitInProgress;
  2881 
  2882 	TInt  errCode   = KErrNone;
  2883 	TBool anyLocked = EFalse;
  2884 
  2885 	if (mmcError != KMMCErrNone)
  2886 		{
  2887 		//
  2888 		// StackSessionCB is the completion callback for the internal initialisation/power-up
  2889 		// session, so we never expect a callback while initialisation is still in progress.
  2890 		// - unless a card has failed to respond and the controller has not detected the error (!)
  2891 		//
  2892 		errCode = KErrTimedOut;	// this error code is not sticky, so should allow stack to be powered up again
  2893 		iInitialise = EFalse;
  2894 		iStackState &= ~(KMMCStackStateInitInProgress | KMMCStackStateInitPending | KMMCStackStateBusInconsistent);
  2895 		}
  2896 	else
  2897 		{
  2898 		if (! iCardArray->CardsPresent())
  2899 			{
  2900 			errCode = KErrNotReady;
  2901 			}
  2902 		else
  2903 			{
  2904 			// Stack initialized ok, so complete request or start auto-unlock
  2905 
  2906 			iInitState = EISDone;
  2907 
  2908 			// remove bindings from password store for cards that do not have passwords
  2909 			TUint i;
  2910 			for (i = 0; i < iMaxCardsInStack; ++i)
  2911 				{
  2912 				TMMCard& cd = *(iCardArray->CardP(i));
  2913 				if (cd.IsPresent())
  2914 					{
  2915 					if (cd.HasPassword())
  2916 						anyLocked = ETrue;
  2917 					else
  2918 						{
  2919 						TMapping* pmp = iSocket->iPasswordStore->FindMappingInStore(cd.CID());
  2920 						if (pmp)
  2921 							pmp->iState = TMapping::EStInvalid;
  2922 						}
  2923 					}	// if (cd.IsPresent())
  2924 				}	// for (i = 0; i < iMaxCardsInStack; ++i)
  2925 
  2926 			// if any cards are locked then launch auto-unlock mechanism
  2927 			if (anyLocked)
  2928 				{
  2929 				//
  2930 				// During power up (stack session context), we use the iAutoUnlockSession
  2931 				// to perform auto-unlock of the cards.  Upon completion of the AutoUnlock
  2932 				// state machine, the local media subsystem is notified via ::PowerUpSequenceComplete
  2933 				//
  2934 				iAutoUnlockSession.SetStack(this);
  2935 				iAutoUnlockSession.SetupCIMAutoUnlock();
  2936 
  2937 				errCode = iAutoUnlockSession.Engage();
  2938 				if(errCode == KErrNone)
  2939 					{
  2940 					// don't complete power up request yet
  2941 					//  - This will be done in DMMCStack::AutoUnlockCB()
  2942 					OstTraceFunctionExit1( DMMCSTACK_STACKSESSIONCB_EXIT2, this );
  2943 					return 0;
  2944 					}
  2945 				}
  2946 			}	// else ( !iCardArray->CardsPresent() )
  2947 		}
  2948 
  2949 	if(errCode == KErrNone)
  2950 		{
  2951 		//
  2952 		// No cards are locked (otherwise we will have engaged iAutoUnlockSession) and we
  2953 		// have encountered no error, so can now continue with the second-stage initialisation
  2954 		// phase (InitStackAfterUnlock).  This performs initialisation that can only be
  2955 		// performed when a card is unlocked (such as setting bus width, speed class etc..)
  2956 		//
  2957 		// iAutoUnlockSession::AutoUnlockCB will complete power-up by calling ::PowerUpSequenceComplete
  2958 		//
  2959 		iAutoUnlockSession.SetStack(this);
  2960 		iAutoUnlockSession.iCardP = NULL;
  2961 		iAutoUnlockSession.SetupCIMInitStackAfterUnlock();
  2962 		errCode = iAutoUnlockSession.Engage();
  2963 		}
  2964 
  2965 	if(errCode != KErrNone)
  2966 		{
  2967 		//
  2968 		// We have encountered an error during power up initialisation
  2969 		//  - Complete the request and notify the local media subsystem.
  2970 		//
  2971 
  2972 		// Calling PowerUpSequenceComplete() with an error may result in the media driver being closed which will delete
  2973 		// the media driver's session, so the stack must be made re-entrant here to allow all references to any engaged 
  2974 		// sessions to be removed from the stack immediately to prevent the stack from referencing a deleted object
  2975 		__ASSERT_ALWAYS(iStackState & KMMCStackStateRunning, DMMCSocket::Panic(DMMCSocket::EMMCNotInDfcContext));
  2976 		iStackState &= ~KMMCStackStateRunning;
  2977 		iSocket->PowerUpSequenceComplete(errCode);
  2978 		iStackState |= KMMCStackStateRunning;
  2979 
  2980 		}
  2981 
  2982 	OstTraceFunctionExit1( DMMCSTACK_STACKSESSIONCB_EXIT3, this );
  2983 	return 0;
  2984 	}
  2985 
  2986 void DMMCStack::AutoUnlockCBST(TAny *aStackP)
  2987 	{
  2988 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:aucbs"));
  2989 
  2990 	static_cast<DMMCStack *>(aStackP)->AutoUnlockCB();
  2991 	}
  2992 
  2993 
  2994 TInt DMMCStack::AutoUnlockCB()
  2995 	{
  2996 	OstTraceFunctionEntry1( DMMCSTACK_AUTOUNLOCKCB_ENTRY, this );
  2997 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:aucb"));
  2998 
  2999 	// This is the session end callback for iAutoUnlockSession,
  3000 	// called at the end of the power up and initialisation process.
  3001 
  3002 	TInt epocErr = iAutoUnlockSession.EpocErrorCode();
  3003 
  3004 	// Calling PowerUpSequenceComplete() with an error may result in the media driver being closed which will delete
  3005 	// the media driver's session, so the stack must be made re-entrant here to allow all references to any engaged 
  3006 	// sessions to be removed from the stack immediately to prevent the stack from referencing a deleted object
  3007 	__ASSERT_ALWAYS(iStackState & KMMCStackStateRunning, DMMCSocket::Panic(DMMCSocket::EMMCNotInDfcContext));
  3008 	if (epocErr != KErrNone)
  3009 		iStackState &= ~KMMCStackStateRunning;
  3010 	iSocket->PowerUpSequenceComplete(epocErr);
  3011 	iStackState |= KMMCStackStateRunning;
  3012 
  3013 	OstTraceFunctionExit1( DMMCSTACK_AUTOUNLOCKCB_EXIT, this );
  3014 	return 0;
  3015 	}
  3016 
  3017 
  3018 inline TMMCErr DMMCStack::AttachCardSM()
  3019 /**
  3020  * This SM function must be invoked by every session which is CardControlled.
  3021  *
  3022  * Some commands require that the data held by the stack for a given card is up to date. 
  3023  *
  3024  * These are card controlled commands. Before such commands are issued, this function should 
  3025  * first be invoked which performs the SEND_STATUS (CMD13) command. 
  3026  *
  3027  * @return MMC error code
  3028  */
  3029 	{
  3030 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ac"));
  3031 
  3032 		enum states
  3033 			{
  3034 			EStBegin=0,
  3035 			EStAttStatus,
  3036 			EStEnd
  3037 			};
  3038 
  3039 		DMMCSession& s=Session();
  3040 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_ATTACHCARDSM1, "Current session=0x%x", &s );
  3041 
  3042 	SMF_BEGIN
  3043 
  3044 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ATTACHCARDSM2, "EStBegin" );
  3045 		if( s.iCardP == NULL )
  3046 		    {
  3047 			OstTraceFunctionExitExt( DMMCSTACK_ATTACHCARDSM_EXIT1, this, (TInt) KMMCErrNoCard );
  3048 			return KMMCErrNoCard;
  3049 		    }
  3050 
  3051 		if( s.iCardP->iUsingSessionP != NULL && s.iCardP->iUsingSessionP != &s )
  3052 			{
  3053 			s.SynchBlock( KMMCBlockOnCardInUse );
  3054 			SMF_WAIT
  3055 			}
  3056 
  3057 		if( s.iCardP->IsPresent() && s.iCardP->iCID == s.iCID )
  3058 			s.iCardP->iUsingSessionP = &s;
  3059 		else
  3060 		    {
  3061 			OstTraceFunctionExitExt( DMMCSTACK_ATTACHCARDSM_EXIT2, this, (TInt) KMMCErrNoCard );
  3062 			return KMMCErrNoCard;
  3063 		    }
  3064 
  3065 		s.iConfig.SetMode( KMMCModeCardControlled );	// for future context switching
  3066 		iConfig.SetMode( KMMCModeCardControlled );		// for this context
  3067 
  3068 		// read card status if there are sticky bits in it
  3069 		if( (TUint32(s.iCardP->iStatus) & KMMCStatClearByReadMask) == 0 ||
  3070 			s.iCardP->iLastCommand == ECmdSendStatus ||
  3071 			s.iSessionID == ECIMNakedSession )
  3072 			SMF_EXIT
  3073 
  3074 		s.PushCommandStack();
  3075 		s.FillCommandDesc( ECmdSendStatus, 0 );
  3076 		m.SetTraps( KMMCErrBasic );		// to restore command stack position to its original level
  3077 		SMF_INVOKES( ExecCommandSMST, EStAttStatus )
  3078 
  3079 	SMF_STATE(EStAttStatus)
  3080 
  3081 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ATTACHCARDSM3, "EStAttStatus" );
  3082 		s.PopCommandStack();
  3083 		OstTraceFunctionExitExt( DMMCSTACK_ATTACHCARDSM_EXIT3, this, (TInt) err );
  3084 		SMF_RETURN( err )
  3085 
  3086 	SMF_END
  3087 	}
  3088 
  3089 inline TMMCErr DMMCStack::CIMInitStackSM()
  3090 /**
  3091  * Performs the Perform the CIM_INIT_STACK macro.
  3092  * @return MMC error code
  3093  */
  3094 	{
  3095 		enum states
  3096 			{
  3097 			EStBegin=0,
  3098 			EStInitDone,
  3099 			EStEnd
  3100 			};
  3101 
  3102 		__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:InitStackSM"));
  3103 
  3104 		DMMCSession& s=Session();
  3105 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMINITSTACKSM1, "Current session=0x%x", &s );
  3106 
  3107 	SMF_BEGIN
  3108 
  3109 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMINITSTACKSM2, "EStBegin" );
  3110 		m.SetTraps( KMMCErrAll );	// to prevent this macro from infinite restarts via iInitialise
  3111 
  3112 		SMF_INVOKES( CIMUpdateAcqSMST, EStInitDone )
  3113 
  3114 	SMF_STATE(EStInitDone)
  3115 
  3116 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMINITSTACKSM3, "EStInitDone" );
  3117 		s.iState &= ~KMMCSessStateInProgress;	// now we won't be restarted
  3118 		SchedGetOnDFC();						// StackSessionCB must be on DFC
  3119 		OstTraceFunctionExitExt( DMMCSTACK_CIMINITSTACKSM_EXIT, this, (TInt) err );
  3120 		SMF_RETURN( err )						// _?_ power cycles can be performed here if error
  3121 
  3122 	SMF_END
  3123 	}
  3124 
  3125 TMMCErr DMMCStack::CIMUpdateAcqSM()
  3126 /**
  3127  * Performs an identification of a card stack. New cards are always
  3128  * initialised but if KMMCStackStateInitInProgress is FALSE then existing
  3129  * cards keep their configuration.
  3130  * After successful execution of this function, all cards will be in standby
  3131  * state.
  3132  * If iPoweredUp is FALSE then the stack is powered up and a full INIT_STACK 
  3133  * is performed (i.e all cards set to idle and then initialized). 
  3134  * @return MMC error code
  3135  */
  3136 	{
  3137 		enum states
  3138 			{
  3139 			EStBegin=0,
  3140 			EStPoweredUp,
  3141 			EStClockOn,
  3142 			EStStartInterrogation,
  3143 			EStCheckStack,
  3144             EStCardCap,
  3145 			EStIssueDSR,
  3146 			EStFinishUp,
  3147 			EStEnd
  3148 			};
  3149 
  3150 		__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:UpdAcqSM"));
  3151 
  3152 		DMMCSession& s=Session();
  3153 		DMMCPsu* psu=(DMMCPsu*)iSocket->iVcc;
  3154 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM1, "Current session=0x%x", &s );
  3155 
  3156 	SMF_BEGIN
  3157 
  3158 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM2, "EStBegin" );
  3159 		// This macro works naked and must not be preempted
  3160 		iConfig.RemoveMode( KMMCModeEnablePreemption | KMMCModeCardControlled );
  3161 		// Ensure DFC is running before and after powering up
  3162 		if( SchedGetOnDFC() )	// Such a direct synchronisation with Scheduler() can only
  3163 			SMF_WAIT			// be used in this macro
  3164 
  3165 		s.iState |= (KMMCSessStateInProgress | KMMCSessStateCritical);
  3166 
  3167 		if (iPoweredUp)
  3168 			SMF_GOTOS( EStPoweredUp )
  3169 
  3170 		// The bus is not powered so all cards need initialising - enforce INIT_STACK.
  3171 		iStackState |= KMMCStackStateInitInProgress;
  3172 
  3173 		// Need to turn on the PSU at it's default voltage. Let the ASSP layer choose
  3174 		// this voltage by calling SetVoltage() with the full range the ASSP supports. 
  3175 		iCurrentOpRange=(psu->VoltageSupported() & ~KMMCAdjustableOpVoltage);
  3176 		psu->SetVoltage(iCurrentOpRange);
  3177 		SMF_INVOKES( DoPowerUpSMST, EStPoweredUp )
  3178 
  3179 	SMF_STATE(EStPoweredUp)
  3180 
  3181 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM3, "EStPoweredUp" );
  3182 		// Switch on the bus clock in identification mode
  3183 		SetBusConfigDefaults(iMasterConfig.iBusConfig, KMMCBusClockFOD);
  3184 		DoSetClock(KMMCBusClockFOD);
  3185 
  3186 		// Make sure controller is in 1-bit bus width mode
  3187 		DoSetBusWidth(EBusWidth1);
  3188 
  3189 		MergeConfig(&s);	// This might take some time, but we are running in DFC here
  3190 		// Reinstate config bits after the merge
  3191 		iConfig.RemoveMode( KMMCModeEnablePreemption | KMMCModeCardControlled );
  3192 		SMF_INVOKES( InitClockOnSMST, EStClockOn )	// Feed init clock to the bus
  3193 
  3194 	SMF_STATE(EStClockOn)
  3195 
  3196 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM4, "EStClockOn" );
  3197 		// Check if there are any cards present in the stack
  3198 		if (!HasCardsPresent())
  3199 			SMF_GOTOS( EStCheckStack )
  3200 
  3201 		if( !InitStackInProgress() )
  3202 			SMF_GOTOS( EStStartInterrogation )
  3203 
  3204 		// Increment the stack's initialiser pass number. Set the current session's pass
  3205 		// number to the new value. Pass number may be used later on to detect sessions
  3206 		// which have been re-initialized due to problems on the bus. 
  3207 		if ((++iInitContext) == 0)		
  3208 			iInitContext++;				// Pass number must never be zero
  3209 		s.iInitContext = iInitContext;	// this session is always in a proper context
  3210 
  3211 	SMF_STATE(EStStartInterrogation)
  3212 
  3213 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM5, "EStStartInterrogation" );
  3214 		// NB: RCAs are not unlocked here. They will be unlocked one by one during the update of card info array.
  3215 		SMF_INVOKES( AcquireStackSMST, EStCheckStack )
  3216 
  3217 	SMF_STATE(EStCheckStack)
  3218 
  3219 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM6, "EStCheckStack" );
  3220 		// Check that all known cards are still present by issuing select/deselect
  3221 		SMF_INVOKES( CheckStackSMST, EStCardCap )
  3222 
  3223 	SMF_STATE(EStCardCap)
  3224 
  3225 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM7, "EStCardCap" );
  3226 		// Call a licencee-specific state machine to allow card capabilities to be modified.
  3227 		SMF_INVOKES( ModifyCardCapabilitySMST, EStIssueDSR )
  3228 
  3229 	SMF_STATE(EStIssueDSR)
  3230 
  3231 		// Now that we have updated the card entries, do any final initialisation
  3232 		// of the card entries and determine the maximum bus clock that can be employed.
  3233 		//
  3234 		// If the bus is not multiplexed (ie - MMC stack), then the max clock is set to
  3235 		// the lowest common denominator of all cards in the stack.  Otherwise (in the case
  3236 		// of a multiplexed bus such as SD), the highest clock is returned and the clock
  3237 		// rate is changed when a new card is selected.
  3238 		//
  3239 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM8, "EStIssueDSR" );
  3240 		TUint maxClk;
  3241 		iCardArray->UpdateAcquisitions(&maxClk);
  3242 		SetBusConfigDefaults( iMasterConfig.iBusConfig, maxClk );
  3243 		DoSetClock(maxClk);
  3244 
  3245 		// merge clock from iMasterConfig.iBusConfig.iBusClock to 
  3246 		// iConfig.iBusConfig.iBusClock - which the PSL should use to configure it's clock
  3247 		MergeConfig(&s);	
  3248 
  3249 		// switch to normal iConfig clock mode
  3250 		InitClockOff();
  3251 		
  3252 	SMF_STATE(EStFinishUp)
  3253 
  3254 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM9, "EStFinishUp" );
  3255 		s.iState &= ~(KMMCSessStateInProgress | KMMCSessStateCritical);
  3256 
  3257 		// Update/Init stack has been completed. 
  3258 
  3259 	SMF_END
  3260 	}
  3261 
  3262 
  3263 #define MHZ_TO_KHZ(valInMhz) ((valInMhz) * 1000)
  3264 
  3265 EXPORT_C TMMCErr DMMCStack::InitStackAfterUnlockSM()
  3266 /**
  3267  * Perform last-stage initialisation of the MMC card.
  3268  * This implements initialiation that must occur only when the card
  3269  * is unlocked (ie - immediately after unlocking, or during initialisation
  3270  * if the card is already unlocked)
  3271  */
  3272 	{
  3273 		enum states
  3274 			{
  3275 			EStBegin=0,
  3276 			EStTestNextCard,
  3277 			EStGetExtendedCSD,
  3278 			EStGotExtendedCSD,
  3279 			EStGotModifiedExtendedCSD,
  3280 			EStEraseGroupDefSet,
  3281 			EStDetermineBusWidthAndClock,
  3282 			EStGotBusWidthAndClock,	
  3283 			EStNoMoreCards,
  3284 			EStExit,
  3285 			EStEnd
  3286 			};
  3287 
  3288 	DMMCSession& s = Session();
  3289 	TBool initSingleCard = (s.CardP() == NULL) ? (TBool)EFalse : (TBool)ETrue;
  3290 	OstTrace1( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM1, "Current session=0x%x", &s );
  3291 
  3292 	SMF_BEGIN
  3293 
  3294 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM2, "EStBegin" );
  3295 		if(initSingleCard)
  3296 			{
  3297 			iSelectedCardIndex = iCxCardCount;
  3298 			TMMCard* cardP = iCardArray->CardP(iSelectedCardIndex);
  3299 
  3300 			// if card not present or is locked, exit
  3301 			if ((!cardP->IsPresent()) || (cardP->IsLocked()))
  3302 				SMF_GOTOS(EStExit);
  3303 
  3304 			s.SetCard(cardP);
  3305 
  3306 			// If a card is currently indexed for initialisation, then only configure this one.  
  3307 			// We assume that this has been called from the SD stack, so only one MMC card will be present on the bus
  3308 
  3309 			SMF_GOTOS(EStGetExtendedCSD);
  3310 			}
  3311 
  3312 		// Initialising the entire MMC stack - start with the first card
  3313 		iSelectedCardIndex = -1;
  3314 		
  3315 		// ...fall through...
  3316 
  3317 	SMF_STATE(EStTestNextCard)
  3318 
  3319 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM3, "EStTestNextCard" );
  3320 
  3321 		// any more cards ?
  3322 		if (++iSelectedCardIndex >= iCxCardCount)
  3323 			SMF_GOTOS(EStNoMoreCards);
  3324 
  3325 		// if no card in this slot, try next one
  3326 		if (!iCardArray->CardP(iSelectedCardIndex)->IsPresent())
  3327 			SMF_GOTOS(EStTestNextCard);
  3328 
  3329 		TMMCard* cardP = iCardArray->CardP(iSelectedCardIndex);
  3330 		s.SetCard(cardP);
  3331 
  3332 		// if card is locked, try the next one
  3333 		if(cardP->IsLocked())
  3334 			SMF_GOTOS(EStTestNextCard);
  3335 
  3336 	SMF_STATE(EStGetExtendedCSD)
  3337 
  3338 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM4, "EStGetExtendedCSD" );
  3339 	
  3340 		// Get the Extended CSD if this is an MMC version 4 card
  3341 
  3342 		__KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), SpecVers() %u", s.CardP()->CSD().SpecVers()));
  3343 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM5, "SpecVers()=%u", s.CardP()->CSD().SpecVers() );
  3344 		
  3345 
  3346 		// clear the Extended CSD contents in case this is a pre-version 4 card or the read fails.
  3347 		memset(s.CardP()->iExtendedCSD.Ptr(), 0, KMMCExtendedCSDLength);
  3348 
  3349 		if (s.CardP()->CSD().SpecVers() < 4) 
  3350 			SMF_GOTOS(EStTestNextCard);
  3351 
  3352 		m.SetTraps(KMMCErrResponseTimeOut | KMMCErrStatus | KMMCErrDataCRC | KMMCErrBypass);	// KMMCErrDataCRC will pick up if the card is not in 1-bit mode
  3353 
  3354 		s.FillCommandDesc(ECmdSendExtendedCSD);
  3355 		s.FillCommandArgs(0, KMMCExtendedCSDLength, iPSLBuf, KMMCExtendedCSDLength);
  3356 
  3357 		__KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), Sending ECmdSendExtendedCSD"));
  3358 		SMF_INVOKES(CIMReadWriteBlocksSMST, EStGotExtendedCSD)
  3359 
  3360 	SMF_STATE(EStGotExtendedCSD)
  3361 		
  3362 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM6, "EStGotExtendedCSD" );
  3363 		if (err != KMMCErrNone)
  3364 			{
  3365 			SMF_GOTOS(EStExit);
  3366 			}
  3367 
  3368 		memcpy(s.CardP()->iExtendedCSD.Ptr(), iPSLBuf, KMMCExtendedCSDLength);
  3369 
  3370 		// Call a licencee-specific state machine to allow the Extended CSD register to be modified.
  3371 		SMF_INVOKES( ModifyCardCapabilitySMST, EStGotModifiedExtendedCSD )
  3372 
  3373 	SMF_STATE(EStGotModifiedExtendedCSD)
  3374 
  3375 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM7, "EStGotExtendedCSD" );
  3376 	
  3377 		__KTRACE_OPT(KPBUS1, Kern::Printf("Extended CSD"));
  3378 		__KTRACE_OPT(KPBUS1, Kern::Printf("CSDStructureVer:            %u", s.CardP()->ExtendedCSD().CSDStructureVer()));
  3379 		__KTRACE_OPT(KPBUS1, Kern::Printf("ExtendedCSDRev:             %u", s.CardP()->ExtendedCSD().ExtendedCSDRev()));
  3380 		__KTRACE_OPT(KPBUS1, Kern::Printf("-------------------------------"));
  3381 		__KTRACE_OPT(KPBUS1, Kern::Printf("SupportedCmdSet:            %u", s.CardP()->ExtendedCSD().SupportedCmdSet()));
  3382 		__KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass26Mhz360V:        0x%02X", s.CardP()->ExtendedCSD().PowerClass26Mhz360V()));
  3383 		__KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass52Mhz360V:        0x%02X", s.CardP()->ExtendedCSD().PowerClass52Mhz360V()));
  3384 		__KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass26Mhz195V:        0x%02X", s.CardP()->ExtendedCSD().PowerClass26Mhz195V()));
  3385 		__KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass52Mhz195V:        0x%02X", s.CardP()->ExtendedCSD().PowerClass52Mhz195V()));
  3386 		__KTRACE_OPT(KPBUS1, Kern::Printf("CardType:                   %u", s.CardP()->ExtendedCSD().CardType()));
  3387 		__KTRACE_OPT(KPBUS1, Kern::Printf("CmdSet:                     %u", s.CardP()->ExtendedCSD().CmdSet()));
  3388 		__KTRACE_OPT(KPBUS1, Kern::Printf("CmdSetRev:                  %u", s.CardP()->ExtendedCSD().CmdSetRev()));
  3389 		__KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass:                 %u", s.CardP()->ExtendedCSD().PowerClass()));
  3390 		__KTRACE_OPT(KPBUS1, Kern::Printf("HighSpeedTiming:            %u", s.CardP()->ExtendedCSD().HighSpeedTiming()));
  3391 		__KTRACE_OPT(KPBUS1, Kern::Printf("HighCapacityEraseGroupSize: %u", s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize()));
  3392 		__KTRACE_OPT(KPBUS1, Kern::Printf("AccessSize:                 %u", s.CardP()->ExtendedCSD().AccessSize()));
  3393 		__KTRACE_OPT(KPBUS1, Kern::Printf("BootInfo:                   %u", s.CardP()->ExtendedCSD().BootInfo() ));
  3394 		__KTRACE_OPT(KPBUS1, Kern::Printf("BootSizeMultiple:           %u", s.CardP()->ExtendedCSD().BootSizeMultiple() ));
  3395 		__KTRACE_OPT(KPBUS1, Kern::Printf("EraseTimeoutMultiple:       %u", s.CardP()->ExtendedCSD().EraseTimeoutMultiple() ));
  3396 		__KTRACE_OPT(KPBUS1, Kern::Printf("ReliableWriteSector:        %u", s.CardP()->ExtendedCSD().ReliableWriteSector() ));
  3397 		__KTRACE_OPT(KPBUS1, Kern::Printf("HighCapWriteProtGroupSize:  %u", s.CardP()->ExtendedCSD().HighCapacityWriteProtectGroupSize() ));
  3398 		__KTRACE_OPT(KPBUS1, Kern::Printf("SleepCurrentVcc:            %u", s.CardP()->ExtendedCSD().SleepCurrentVcc() ));
  3399 		__KTRACE_OPT(KPBUS1, Kern::Printf("SleepCurrentVccQ:           %u", s.CardP()->ExtendedCSD().SleepCurrentVccQ()));
  3400 		__KTRACE_OPT(KPBUS1, Kern::Printf("SleepAwakeTimeout:          %u", s.CardP()->ExtendedCSD().SleepAwakeTimeout()));
  3401 		__KTRACE_OPT(KPBUS1, Kern::Printf("BootConfig:                 %u", s.CardP()->ExtendedCSD().BootConfig()));
  3402 		__KTRACE_OPT(KPBUS1, Kern::Printf("BootBusWidth:               %u", s.CardP()->ExtendedCSD().BootBusWidth()));
  3403 		__KTRACE_OPT(KPBUS1, Kern::Printf("EraseGroupDef:              %u", s.CardP()->ExtendedCSD().EraseGroupDef()));
  3404 		
  3405 		OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM8, "CSDStructureVer=%u; ExtendedCSDRev=%u; SupportedCmdSet=%u", s.CardP()->ExtendedCSD().CSDStructureVer(), s.CardP()->ExtendedCSD().ExtendedCSDRev(), s.CardP()->ExtendedCSD().SupportedCmdSet() );
  3406 		OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM9, "PowerClass26Mhz360V=0x%02x; PowerClass52Mhz360V=0x%02x; PowerClass26Mhz195V=0x%02x; PowerClass52Mhz195V=0x%02x", s.CardP()->ExtendedCSD().PowerClass26Mhz360V(), s.CardP()->ExtendedCSD().PowerClass52Mhz360V(), s.CardP()->ExtendedCSD().PowerClass26Mhz195V(), s.CardP()->ExtendedCSD().PowerClass52Mhz195V() );
  3407 		OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM10, "CardType=%u; CmdSet=%u; CmdSetRev=%u; PowerClass=%u; HighSpeedTiming=%u", s.CardP()->ExtendedCSD().CardType(), s.CardP()->ExtendedCSD().CmdSet(), s.CardP()->ExtendedCSD().CmdSetRev(), s.CardP()->ExtendedCSD().PowerClass(), s.CardP()->ExtendedCSD().HighSpeedTiming() );
  3408 		OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM11, "HighCapacityEraseGroupSize=%u; AccessSize=%u; BootInfo=%u; BootSizeMultiple=%u; EraseTimeoutMultiple=%u", s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize(), s.CardP()->ExtendedCSD().AccessSize(), s.CardP()->ExtendedCSD().BootInfo(), s.CardP()->ExtendedCSD().BootSizeMultiple(), s.CardP()->ExtendedCSD().EraseTimeoutMultiple() );
  3409 		OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM12, "ReliableWriteSector=%u; HighCapWriteProtGroupSize=%u; SleepCurrentVcc=%u; SleepCurrentVccQ=%u; SleepAwakeTimeout=%u", s.CardP()->ExtendedCSD().ReliableWriteSector(), s.CardP()->ExtendedCSD().HighCapacityWriteProtectGroupSize(), s.CardP()->ExtendedCSD().SleepCurrentVcc(), s.CardP()->ExtendedCSD().SleepCurrentVccQ(), s.CardP()->ExtendedCSD().SleepAwakeTimeout() );
  3410 		OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM13, "BootConfig=%u; BootBusWidth=%u; EraseGroupDef=%u", s.CardP()->ExtendedCSD().BootConfig(), s.CardP()->ExtendedCSD().BootBusWidth(), s.CardP()->ExtendedCSD().EraseGroupDef() );
  3411 		
  3412 		if (s.CardP()->ExtendedCSD().ExtendedCSDRev() >= 3)
  3413 			{
  3414 			if (!(s.CardP()->ExtendedCSD().EraseGroupDef()) && s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize())
  3415 				{
  3416 				// Need to ensure that media is using correct erase group sizes.
  3417 				TMMCArgument arg = TExtendedCSD::GetWriteArg(
  3418 					TExtendedCSD::EWriteByte,
  3419 					TExtendedCSD::EEraseGroupDefIndex,
  3420 					TExtendedCSD::EEraseGrpDefEnableHighCapSizes,
  3421 					0);
  3422 	
  3423 				__KTRACE_OPT(KPBUS1, Kern::Printf(">Writing to EXT_CSD (EEraseGroupDefIndex), arg %08X", (TUint32) arg));
  3424 				OstTrace1( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM14, "Writing to EXT_CSD (EEraseGroupDefIndex); arg=0x%08x", (TUint32) arg );
  3425 				
  3426 				s.FillCommandDesc(ECmdSwitch, arg);
  3427 				
  3428 				SMF_INVOKES(ExecSwitchCommandST, EStEraseGroupDefSet)
  3429 				}
  3430 			}
  3431 		
  3432 		SMF_GOTOS(EStDetermineBusWidthAndClock)
  3433 		
  3434 	SMF_STATE(EStEraseGroupDefSet)
  3435 	
  3436 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM15, "EStEraseGroupDefSet" );
  3437 	
  3438 		if (err == KMMCErrNone)
  3439 			{
  3440 			// EEraseGroupDef has been updated succussfully, 
  3441 			// update the Extended CSD to reflect this			
  3442 			memset( s.CardP()->iExtendedCSD.Ptr()+TExtendedCSD::EEraseGroupDefIndex, TExtendedCSD::EEraseGrpDefEnableHighCapSizes, 1);
  3443 			}
  3444 	
  3445 	SMF_STATE(EStDetermineBusWidthAndClock)
  3446 	
  3447 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM16, "EStDetermineBusWidthAndClock" );
  3448 		SMF_INVOKES( DetermineBusWidthAndClockSMST, EStGotBusWidthAndClock )
  3449 
  3450     SMF_STATE(EStGotBusWidthAndClock)
  3451 
  3452 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM17, "EStGotBusWidthAndClock" );
  3453 		SMF_NEXTS(initSingleCard ? EStExit : EStTestNextCard)
  3454 
  3455 		if(iMultiplexedBus || iCardArray->CardsPresent() == 1)
  3456 			{
  3457 			SMF_CALL( ConfigureHighSpeedSMST )
  3458 			}
  3459 		
  3460 		SMF_GOTONEXTS
  3461 
  3462 	SMF_STATE(EStNoMoreCards)
  3463 
  3464 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM18, "EStNoMoreCards" );
  3465 
  3466 	SMF_STATE(EStExit)
  3467 	
  3468 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM19, "EStExit" );
  3469 		m.ResetTraps();
  3470 
  3471 	SMF_END
  3472 	}
  3473 
  3474 
  3475 
  3476 /**
  3477 DetermineBusWidthAndClockSM()
  3478 
  3479 Reads the extended CSD register for all MMCV4 cards in the stack.
  3480 If there is only one MMCV4 card, then an attempt is made to switch
  3481 both the card and the controller to a higher clock rate (either 26MHz of 52MHz) 
  3482 and to a wider bus width (4 or 8 bits). 
  3483 The clock speed & bus width chosen depend on :
  3484 
  3485 - whether the card supports it
  3486 - whether the controller supports it
  3487 - whether the controller has the ability to supply enough current (the current used 
  3488   by the card can be read from the Extended CSD register)
  3489 
  3490 */
  3491 TMMCErr DMMCStack::DetermineBusWidthAndClockSM()
  3492 	{
  3493 		enum states
  3494 			{
  3495 			EStBegin=0,
  3496 			EStWritePowerClass,
  3497 			EStStartBusTest,
  3498 			EStExit,
  3499 			EStEnd
  3500 			};
  3501 
  3502 	DMMCSession& s = Session();
  3503 	TMMCard* cardP = iCardArray->CardP(iSelectedCardIndex);
  3504 	OstTrace1( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM1, "Current session=0x%x", &s );
  3505 
  3506 	SMF_BEGIN
  3507 	
  3508 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM2, "EStBegin" );
  3509 		// Trap Switch errors & no-response errors
  3510 		m.SetTraps(KMMCErrResponseTimeOut | KMMCErrStatus);
  3511 
  3512 		__KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), iCxCardCount %u", iCxCardCount));
  3513 
  3514 
  3515 	SMF_STATE(EStWritePowerClass)
  3516 
  3517 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM3, "EStWritePowerClass" );
  3518 	
  3519 		// Check the card type is valid
  3520 		// The only currently valid values for this field are 0x01 or 0x03
  3521 		TUint cardType = cardP->iExtendedCSD.CardType();
  3522 		if (cardType != (TExtendedCSD::EHighSpeedCard26Mhz) && 
  3523 			cardType != (TExtendedCSD::EHighSpeedCard26Mhz | TExtendedCSD::EHighSpeedCard52Mhz))
  3524 			{
  3525 			__KTRACE_OPT(KPBUS1, Kern::Printf("Unsupported card type %u", cardType));
  3526 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM4, "Unsupported card type=%u", cardType );
  3527 			
  3528 			SMF_GOTOS(EStExit);
  3529 			}
  3530 
  3531 		// determine the optimum bus width & clock speed which match the power constraints
  3532 		TUint powerClass;
  3533 		DetermineBusWidthAndClock(
  3534 			*cardP, 
  3535 			(iCurrentOpRange == KMMCOCRLowVoltage), 
  3536 			powerClass, 
  3537 			iBusWidthAndClock);
  3538 
  3539 		// If the power class for the chosen width is different from the default,
  3540 		// send SWITCH cmd and write the POWER_CLASS byte of the EXT_CSD register
  3541 		if (powerClass > 0)
  3542 			{
  3543 			TMMCArgument arg = TExtendedCSD::GetWriteArg(
  3544 				TExtendedCSD::EWriteByte,
  3545 				TExtendedCSD::EPowerClassIndex,
  3546 				powerClass,
  3547 				0);
  3548 
  3549 			__KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), Writing to EXT_CSD (EPowerClass), arg %08X", (TUint32) arg));
  3550 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM5, "Writing to EXT_CSD (EPowerClass); arg=0x%08x", (TUint32) arg );
  3551 			s.FillCommandDesc(ECmdSwitch, arg);
  3552 			SMF_INVOKES(ExecSwitchCommandST, EStStartBusTest)
  3553 			}
  3554 
  3555 	SMF_STATE(EStStartBusTest)
  3556 		
  3557         OstTrace0( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM6, "EStStartBusTest" );
  3558         	
  3559 		if (err != KMMCErrNone)
  3560 			{
  3561 			SMF_GOTOS(EStExit);
  3562 			}
  3563 
  3564 		// We have determined the capabilities of the host and card.
  3565 		//  - Before switching to the required bus width, perform the BUSTEST sequence
  3566 		SMF_INVOKES(ExecBusTestSMST, EStExit);
  3567 
  3568 	SMF_STATE(EStExit)
  3569 	
  3570 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM7, "EStExit" );
  3571 		m.ResetTraps();
  3572 
  3573 	SMF_END
  3574 	}
  3575 
  3576 
  3577 /**
  3578 ConfigureHighSpeedSM()
  3579 
  3580 Reads the extended CSD register for all MMCV4 cards in the stack.
  3581 If there is only one MMCV4 card, then an attempt is made to switch
  3582 both the card and the controller to a higher clock rate (either 26MHz of 52MHz) 
  3583 and to a wider bus width (4 or 8 bits). 
  3584 The clock speed & bus width chosen depend on :
  3585 
  3586 - whether the card supports it
  3587 - whether the controller supports it
  3588 - whether the controller has the ability to supply enough current (the current used 
  3589   by the card can be read from the Extended CSD register)
  3590 
  3591 */
  3592 TMMCErr DMMCStack::ConfigureHighSpeedSM()
  3593 	{
  3594 		enum states
  3595 			{
  3596 			EStBegin=0,
  3597 			EStConfigureBusWidth,
  3598 			EStWriteHsTiming,
  3599 			EStConfigureClock,
  3600 			EStExit,
  3601 			EStEnd
  3602 			};
  3603 
  3604 	DMMCSession& s = Session();
  3605 	TMMCard* cardP = iCardArray->CardP(iSelectedCardIndex);
  3606 	OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM1, "Current session=0x%x", &s );
  3607 
  3608 	SMF_BEGIN
  3609 
  3610         OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM2, "EStBegin" );
  3611         
  3612 		// Trap Switch errors & no-response errors
  3613 		m.SetTraps(KMMCErrResponseTimeOut | KMMCErrStatus);
  3614 
  3615 		__KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), iCxCardCount %u", iCxCardCount));
  3616 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM3, "iCxCardCount=%d", iCxCardCount );
  3617 
  3618 		cardP->SetHighSpeedClock(0);
  3619 
  3620 		// Check the card type is valid
  3621 		// The only currently valid values for this field are 0x01 or 0x03
  3622 		TUint cardType = cardP->iExtendedCSD.CardType();
  3623 		if (cardType != (TExtendedCSD::EHighSpeedCard26Mhz) && 
  3624 			cardType != (TExtendedCSD::EHighSpeedCard26Mhz | TExtendedCSD::EHighSpeedCard52Mhz))
  3625 			{
  3626 			__KTRACE_OPT(KPBUS1, Kern::Printf("Unsupported card type %u", cardType));
  3627 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM4, "Unsupported card type=%u", cardType );
  3628 			SMF_GOTOS(EStExit);
  3629 			}
  3630 
  3631 		// If the bus width is 4 or 8, send SWITCH cmd and write the BUS_WIDTH byte of the EXT_CSD register
  3632 
  3633 		if (iBusWidthAndClock != E1Bit20Mhz)
  3634 			{
  3635 			TMMCArgument arg = TExtendedCSD::GetWriteArg(
  3636 				TExtendedCSD::EWriteByte,
  3637 				TExtendedCSD::EBusWidthModeIndex,
  3638 				(iBusWidthAndClock & E4BitMask) ? TExtendedCSD::EExtCsdBusWidth4 : TExtendedCSD::EExtCsdBusWidth8,
  3639 				0);
  3640 
  3641 			__KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), Writing to EXT_CSD (EBusWidthMode), arg %08X", (TUint32) arg));
  3642 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM5, "Writing to EXT_CSD (EBusWidthMode); arg=0x%x", (TUint32) arg );
  3643 			s.FillCommandDesc(ECmdSwitch, arg);
  3644 			SMF_INVOKES(ExecSwitchCommandST, EStConfigureBusWidth)
  3645 			}
  3646 
  3647 	SMF_STATE(EStConfigureBusWidth)
  3648 
  3649         OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM6, "EStConfigureBusWidth" );
  3650         
  3651 		if (err != KMMCErrNone)
  3652 			{
  3653 			SMF_GOTOS(EStExit);
  3654 			}
  3655 
  3656 		// Ensure that the controller is configured for an 4 or 8 bit bus
  3657 		//  - BUSTEST should have already done this
  3658 		if (iBusWidthAndClock & E4BitMask)
  3659 			{
  3660 			DoSetBusWidth(EBusWidth4);
  3661 			}
  3662 		else if (iBusWidthAndClock & E8BitMask)
  3663 			{
  3664 			DoSetBusWidth(EBusWidth8);
  3665 			}
  3666 		// fall through to next state
  3667 
  3668 	SMF_STATE(EStWriteHsTiming)
  3669 	
  3670 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM7, "EStWriteHsTiming" );
  3671 	
  3672 		if (iBusWidthAndClock == E1Bit20Mhz)
  3673 			SMF_GOTOS(EStExit);
  3674 
  3675 		TMMCArgument arg = TExtendedCSD::GetWriteArg(
  3676 			TExtendedCSD::EWriteByte,
  3677 			TExtendedCSD::EHighSpeedInterfaceTimingIndex,
  3678 			1,	// turn on high speed (26 or 52 Mhz, depending on the card type)
  3679 			0);
  3680 
  3681 		__KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), Writing to EXT_CSD (EHighSpeedInterfaceTiming), arg %08X", (TUint32) arg));
  3682 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM8, "Writing to EXT_CSD (EHighSpeedInterfaceTiming); arg=0x%x", (TUint32) arg );
  3683 		s.FillCommandDesc(ECmdSwitch, arg);
  3684 		SMF_INVOKES(ExecSwitchCommandST, EStConfigureClock)
  3685 
  3686 
  3687 	SMF_STATE(EStConfigureClock)
  3688 
  3689 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM9, "EStConfigureClock" );
  3690 	
  3691 		if (err != KMMCErrNone)
  3692 			{
  3693 			DoSetBusWidth(EBusWidth1);
  3694 			SMF_GOTOS(EStExit);
  3695 			}
  3696 
  3697 		cardP->SetHighSpeedClock(
  3698 			MHZ_TO_KHZ(((iBusWidthAndClock & E52MhzMask) ? 
  3699 			            TMMCMachineInfoV4::EClockSpeed52Mhz:
  3700 			            TMMCMachineInfoV4::EClockSpeed26Mhz)));
  3701 
  3702 	SMF_STATE(EStExit)
  3703 	
  3704 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM10, "EStExit" );
  3705 	
  3706 		m.ResetTraps();
  3707 
  3708 	SMF_END
  3709 	}
  3710 
  3711 // Issue a switch command and then wait while he card is in prg state
  3712 //
  3713 TMMCErr DMMCStack::ExecSwitchCommand()
  3714 	{
  3715 		enum states
  3716 			{
  3717 			EStBegin=0,
  3718 			EStSendStatus,
  3719 			EStGetStatus,
  3720 			EStEnd
  3721 			};
  3722 
  3723 		DMMCSession& s=Session();
  3724 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSWITCHCOMMAND1, "Current session=0x%x", &s );
  3725 
  3726 	SMF_BEGIN
  3727     	OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSWITCHCOMMAND2, "EStBegin" );
  3728     	SMF_INVOKES(ExecCommandSMST, EStSendStatus)
  3729 
  3730 	SMF_STATE(EStSendStatus)
  3731 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSWITCHCOMMAND3, "EStSendStatus" );
  3732 		s.FillCommandDesc(ECmdSendStatus, 0);
  3733 		SMF_INVOKES(ExecCommandSMST, EStGetStatus)
  3734 
  3735 	SMF_STATE(EStGetStatus)
  3736 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSWITCHCOMMAND4, "EStGetStatus" );
  3737 		const TMMCStatus st(s.ResponseP());
  3738 
  3739 		const TMMCardStateEnum st1 = st.State();
  3740 		if (st1 == ECardStatePrg)
  3741 			{
  3742 			SMF_INVOKES(ProgramTimerSMST, EStSendStatus);
  3743 			}
  3744 		
  3745 	// Fall through if CURRENT_STATE is not PGM
  3746 
  3747 	SMF_END
  3748 	}
  3749 
  3750 // Issue CMD5 to change device status to Sleep mode
  3751 //
  3752 TMMCErr DMMCStack::ExecSleepCommandSM()
  3753 	{
  3754 		enum states
  3755 			{
  3756 			EStBegin=0,
  3757 			EStIndexNxtCard,
  3758 			EStIssueSleepAwake,
  3759 			EStSleepAwakeIssued,
  3760 			EStUpdateStackState,
  3761 			EStDone,
  3762 			EStEnd
  3763 			};
  3764 
  3765 		DMMCSession& s=Session();
  3766 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM1, "Current session=0x%x", &s );
  3767 
  3768 	SMF_BEGIN
  3769 	
  3770         OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM2, "EStBegin" );
  3771         
  3772 		__KTRACE_OPT(KPBUS1, Kern::Printf(">ExecSleepCommandSM()"));
  3773 		
  3774 		iAutoUnlockIndex = -1;
  3775 		// drop through....
  3776 		
  3777 	SMF_STATE(EStIndexNxtCard)
  3778 	
  3779 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM3, "EStIndexNxtCard" );
  3780 		__KTRACE_OPT(KPBUS1, Kern::Printf(">EStIndexNxtCard"));
  3781 		// the cycle is finished when iAutoUnlockIndex == KMaxMultiMediaCardsPerStack
  3782 		if(iAutoUnlockIndex >= TInt(KMaxMMCardsPerStack))
  3783 			{
  3784 			SMF_GOTOS(EStUpdateStackState);
  3785 			}
  3786 
  3787 		// Potentionaly more than one eMMC device attached to Controller
  3788 		// need to select each device and determine if Sleep can be issued
  3789 		TBool useIndex = EFalse;
  3790 		for (++iAutoUnlockIndex; iAutoUnlockIndex < TInt(KMaxMMCardsPerStack); ++iAutoUnlockIndex)
  3791 			{
  3792 			// card must be present and a valid 4.3 device
  3793 			TMMCard* cardP = iCardArray->CardP(iAutoUnlockIndex);
  3794 			useIndex = ( (cardP->IsPresent()) &&
  3795 					     (cardP->ExtendedCSD().ExtendedCSDRev() >= 3) &&
  3796 						 (cardP->iStatus != ECardStateSlp) );
  3797 
  3798 			// don't increment iAutoUnlockIndex in continuation loop
  3799 			if (useIndex)
  3800 				{
  3801 				__KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: is v4.3 device",iAutoUnlockIndex));
  3802 				OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM4, "Card[%d]: is v4.3+ device", iAutoUnlockIndex );
  3803 				break;
  3804 				}
  3805 			}
  3806 		
  3807 		if (!useIndex)
  3808 			{
  3809 			SMF_GOTOS(EStUpdateStackState);
  3810 			}
  3811 		
  3812 		TMMCard &cd = *(iCardArray->CardP(iAutoUnlockIndex));
  3813 		s.SetCard(&cd);
  3814 		
  3815 		s.PushCommandStack();		
  3816 		s.FillCommandDesc(ECmdSleepAwake, KBit15);
  3817 		
  3818 		// CMD5 is an AC command, ExecCommandSMST will automatically issue a deselect
  3819 		SMF_INVOKES(ExecCommandSMST, EStSleepAwakeIssued)
  3820 		
  3821 	SMF_STATE(EStSleepAwakeIssued)
  3822 		 
  3823 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM5, "EStSleepAwakeIssued" );
  3824 		__KTRACE_OPT(KPBUS1, Kern::Printf(">EStSleepAwakeIssued!"));
  3825 		
  3826 		const TMMCStatus status(s.ResponseP());
  3827 		
  3828 		s.PopCommandStack();
  3829 
  3830 		if(status.State() == ECardStateStby || status.State() == ECardStateSlp)
  3831 			{			
  3832 			// R1b is issued before Sleep state is achieved and 
  3833 			// will therefore return the previous state which was Standby
  3834 			__KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: SLEEP",iAutoUnlockIndex));
  3835 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM6, "Card[%d]: SLEEP", iAutoUnlockIndex );
  3836 			
  3837 			// Ensure card status is ECardStateSlp
  3838 			s.CardP()->iStatus.UpdateState(ECardStateSlp);
  3839 			
  3840 			// Update Stack state to indicate media is sleep mode
  3841 			iStackState |= KMMCStackStateSleep;
  3842 			}
  3843 		else
  3844 			{ 
  3845 			__KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: UNKNOWN",iAutoUnlockIndex));
  3846 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM7, "Card[%d]: UNKNOWN", iAutoUnlockIndex );
  3847 			
  3848 			return (KMMCErrStatus);
  3849 			}
  3850 		
  3851 		SMF_GOTOS(EStIndexNxtCard)
  3852 
  3853 	SMF_STATE(EStUpdateStackState)
  3854 
  3855 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM8, "EStUpdateStackState" );
  3856 		if (iStackState & KMMCStackStateSleep)
  3857 			{ 
  3858 			// Media has been transitioned to sleep state
  3859 			iStackState &= ~KMMCStackStateSleep;
  3860 			
  3861 			// VccCore may now be switched off
  3862 			iSocket->iVccCore->SetState(EPsuOff);
  3863 			}
  3864 //		else
  3865 			// No media transitioned to sleep state or media was already in sleep state,
  3866 			// nothing to do...
  3867 			
  3868 	SMF_STATE(EStDone)
  3869 		
  3870 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM9, "EStDone" );
  3871 		__KTRACE_OPT(KPBUS1, Kern::Printf("<ExecSleepCommandSM()"));
  3872 		
  3873 	SMF_END
  3874 	}
  3875 
  3876 
  3877 //Issue CMD5 to change devices into STANDBY state
  3878 TMMCErr DMMCStack::ExecAwakeCommandSM()
  3879 	{
  3880 		enum states
  3881 			{
  3882 			EStBegin=0,
  3883 			EStPoweredUp,
  3884 			EStAwakeIssued,
  3885 			EStDone,
  3886 			EStEnd
  3887 			};
  3888 
  3889 		DMMCSession& s=Session();
  3890 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM1, "Current session=0x%x", &s );
  3891 
  3892 	SMF_BEGIN
  3893 	
  3894 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM2, "EStBegin" );
  3895 		__KTRACE_OPT(KPBUS1, Kern::Printf(">ExecAwakeCommandSM()"));
  3896 		
  3897 		// Call PSL to ensure VccQ is powered up before continuing
  3898 		SMF_INVOKES( DoWakeUpSMST, EStPoweredUp )
  3899 		
  3900 	SMF_STATE(EStPoweredUp)	
  3901 
  3902 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM3, "EStPoweredUp" );
  3903 		__KTRACE_OPT(KPBUS1, Kern::Printf("VccQ Powered Up"));
  3904 		
  3905 		//Issue CMD5 to awaken media
  3906 		s.PushCommandStack();		
  3907 		s.FillCommandDesc(ECmdSleepAwake);
  3908 		s.Command().iArgument.SetRCA(s.CardP()->RCA());
  3909 		
  3910 		SMF_INVOKES(IssueCommandCheckResponseSMST, EStAwakeIssued)
  3911 		
  3912 	SMF_STATE(EStAwakeIssued)
  3913 		 
  3914 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM4, "EStAwakeIssued" );
  3915 		__KTRACE_OPT(KPBUS1, Kern::Printf(">>EStAwakeIssued!"));
  3916 		
  3917 		TMMCStatus status(s.ResponseP());
  3918 
  3919 		if(status.State() == ECardStateStby || status.State() == ECardStateSlp)
  3920 			{			
  3921 			// R1b is issued before Standby state is achieved and 
  3922 			// will therefore return the previous state which was Sleep
  3923 			__KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: STANDBY",iAutoUnlockIndex));
  3924 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM5, "Card[%d]: STANDBY", iAutoUnlockIndex );
  3925 			s.CardP()->iStatus.UpdateState(ECardStateStby);
  3926 			}
  3927 		else
  3928 			{ 
  3929 			__KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: UNKNOWN",iAutoUnlockIndex));
  3930 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM6, "Card[%d]: UNKNOWN", iAutoUnlockIndex );
  3931 			OstTraceFunctionExitExt( DMMCSTACK_EXECAWAKECOMMANDSM_EXIT, this, (TInt) KMMCErrStatus );
  3932 			return KMMCErrStatus;
  3933 			}
  3934 
  3935 		s.PopCommandStack();	
  3936 
  3937 	SMF_STATE(EStDone)
  3938 	
  3939 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM7, "EStDone" );
  3940 		__KTRACE_OPT(KPBUS1, Kern::Printf("<ExecAwakeCommandSM()"));
  3941 	
  3942 	SMF_END
  3943 	}
  3944 
  3945 
  3946 // determine the maximum bus width and clock speed supported by both the controller
  3947 // and the card which fits the power constraints.
  3948 void DMMCStack::DetermineBusWidthAndClock(
  3949 	const TMMCard& aCard, 
  3950 	TBool aLowVoltage,
  3951 	TUint& aPowerClass,
  3952 	TBusWidthAndClock& aBusWidthAndClock)
  3953 	{
  3954 	OstTraceExt2(TRACE_FLOW, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCK_ENTRY, "DMMCStack::DetermineBusWidthAndClock;aLowVoltage=%d;this=%x", (TInt) aLowVoltage, (TUint) this);
  3955 
  3956 	// Set default return values - in case power constraints aren't matched
  3957 	aPowerClass = 0;
  3958 	aBusWidthAndClock = E1Bit20Mhz;
  3959 
  3960 	// Get the bus widths & clocks supported by the controller
  3961 	// NB If the PSL doesn not support TMMCMachineInfoV4, return
  3962 	TMMCMachineInfoV4 machineInfo;
  3963 	TMMCMachineInfoV4Pckg machineInfoPckg(machineInfo);
  3964 	MachineInfo(machineInfoPckg);
  3965 	if (machineInfo.iVersion < TMMCMachineInfoV4::EVersion4)
  3966 	    {
  3967 		OstTraceFunctionExit1( DMMCSTACK_DETERMINEBUSWIDTHANDCLOCK_EXIT1, this );
  3968 		return;
  3969 	    }
  3970 
  3971 	TBusWidth maxBusWidth = machineInfo.iMaxBusWidth;
  3972 	TInt maxClockSpeedInMhz = machineInfo.iMaxClockSpeedInMhz;
  3973 
  3974 	TUint32 controllerWidthAndClock = E1Bit20Mhz;
  3975 
  3976 	if (maxClockSpeedInMhz >= TMMCMachineInfoV4::EClockSpeed26Mhz && maxBusWidth >= EBusWidth4)
  3977 		controllerWidthAndClock|= E4Bits26Mhz;
  3978 	if (maxClockSpeedInMhz >= TMMCMachineInfoV4::EClockSpeed52Mhz && maxBusWidth >= EBusWidth4)
  3979 		controllerWidthAndClock|= E4Bits52Mhz;
  3980 		
  3981 	if (maxClockSpeedInMhz >= TMMCMachineInfoV4::EClockSpeed26Mhz && maxBusWidth >= EBusWidth8)
  3982 		controllerWidthAndClock|= E8Bits26Mhz;
  3983 	if (maxClockSpeedInMhz >= TMMCMachineInfoV4::EClockSpeed52Mhz && maxBusWidth >= EBusWidth8)
  3984 		controllerWidthAndClock|= E8Bits52Mhz;
  3985 		
  3986 	// Get the bus widths & clocks supported by the card
  3987 	TUint32 cardWidthAndClock = E1Bit20Mhz;
  3988 
  3989 	if (aCard.ExtendedCSD().CardType() & TExtendedCSD::EHighSpeedCard26Mhz)
  3990 		cardWidthAndClock|= E4Bits26Mhz | E8Bits26Mhz;
  3991 	if (aCard.ExtendedCSD().CardType() & TExtendedCSD::EHighSpeedCard52Mhz)
  3992 		cardWidthAndClock|= E4Bits52Mhz | E8Bits52Mhz;
  3993 
  3994 
  3995 	// Get the bus widths & clocks supported by both the controller & card
  3996 	// by AND-ing them together,
  3997 	TUint32 supportedWidthAndClock = controllerWidthAndClock & cardWidthAndClock;
  3998 
  3999 	// Iterate through all the modes (starting at the fastest) until we find one
  4000 	// that is supported by both card & controller and fits the power constraints
  4001 	TUint powerClass = 0;
  4002 	for (TUint targetWidthAndClock = E8Bits52Mhz; targetWidthAndClock != 0; targetWidthAndClock>>= 1)
  4003 		{
  4004 		if ((supportedWidthAndClock & targetWidthAndClock) == 0)
  4005 			continue;
  4006 
  4007 		powerClass = GetPowerClass(aCard, TBusWidthAndClock(targetWidthAndClock), aLowVoltage);
  4008 
  4009 		// can the controller support this power class ?
  4010 		if (powerClass > (aLowVoltage ? machineInfo.iLowVoltagePowerClass : machineInfo.iHighVoltagePowerClass ))
  4011 			continue;
  4012 
  4013 		aPowerClass = powerClass;
  4014 		aBusWidthAndClock = TBusWidthAndClock(targetWidthAndClock);
  4015 		break;
  4016 		}
  4017 
  4018 	__KTRACE_OPT(KPBUS1, Kern::Printf("aPowerClass %u, targetWidthAndClock = %08X", aPowerClass, aBusWidthAndClock));
  4019 	OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCK, "aPowerClass=%u; targetWidthAndClock=0x%08x", aPowerClass, (TUint) aBusWidthAndClock );
  4020 	OstTraceFunctionExit1( DMMCSTACK_DETERMINEBUSWIDTHANDCLOCK_EXIT2, this );
  4021 	}
  4022 
  4023 TUint DMMCStack::GetPowerClass(const TMMCard& aCard, TBusWidthAndClock aWidthAndClock, TBool aLowVoltage)
  4024 	{
  4025 	OstTraceExt3(TRACE_FLOW, DMMCSTACK_GETPOWERCLASS_ENTRY, "DMMCStack::GetPowerClass;aWidthAndClock=%d;aLowVoltage=%d;this=%x", (TInt) aWidthAndClock, (TInt) aLowVoltage, (TUint) this);
  4026 	// The power class for 4 bit bus configurations is in the low nibble,
  4027 	// The power class for 8 bit bus configurations is in the high nibble,
  4028 	#define LO_NIBBLE(val) (val & 0x0F)
  4029 	#define HI_NIBBLE(val) ((val >> 4) & 0x0F)
  4030 
  4031 	const TExtendedCSD& extendedCSD = aCard.ExtendedCSD();
  4032 
  4033 	TUint powerClass = 0;
  4034 
  4035 	if (aLowVoltage)
  4036 		{
  4037 		switch(	aWidthAndClock)
  4038 			{
  4039 			case E4Bits26Mhz:
  4040 				powerClass = LO_NIBBLE(extendedCSD.PowerClass26Mhz195V());
  4041 				break;
  4042 			case E4Bits52Mhz:
  4043 				powerClass = LO_NIBBLE(extendedCSD.PowerClass52Mhz195V());
  4044 				break;
  4045 			case E8Bits26Mhz:
  4046 				powerClass = HI_NIBBLE(extendedCSD.PowerClass26Mhz195V());
  4047 				break;
  4048 			case E8Bits52Mhz:
  4049 				powerClass = HI_NIBBLE(extendedCSD.PowerClass52Mhz195V());
  4050 				break;
  4051 			case E1Bit20Mhz:
  4052 				powerClass = 0;
  4053 				break;
  4054 			}
  4055 		}
  4056 	else
  4057 		{
  4058 		switch(	aWidthAndClock)
  4059 			{
  4060 			case E4Bits26Mhz:
  4061 				powerClass = LO_NIBBLE(extendedCSD.PowerClass26Mhz360V());
  4062 				break;
  4063 			case E4Bits52Mhz:
  4064 				powerClass = LO_NIBBLE(extendedCSD.PowerClass52Mhz360V());
  4065 				break;
  4066 			case E8Bits26Mhz:
  4067 				powerClass = HI_NIBBLE(extendedCSD.PowerClass26Mhz360V());
  4068 				break;
  4069 			case E8Bits52Mhz:
  4070 				powerClass = HI_NIBBLE(extendedCSD.PowerClass52Mhz360V());
  4071 				break;
  4072 			case E1Bit20Mhz:
  4073 				powerClass = 0;
  4074 				break;
  4075 			}
  4076 		}
  4077 
  4078 		OstTraceFunctionExitExt( DMMCSTACK_GETPOWERCLASS_EXIT, this, powerClass );
  4079 		return powerClass;
  4080 	}
  4081 
  4082 //
  4083 // Execute the BUSTEST procedure for a given bus width
  4084 //
  4085 TMMCErr DMMCStack::ExecBusTestSM()
  4086 	{
  4087 	enum states
  4088 		{
  4089 		EStBegin=0,
  4090 		EstSendBusTest_W,
  4091 		EstSendBusTest_R,
  4092 		EstGotBusTest_R,
  4093 		EStExit,
  4094 		EStEnd
  4095 		};
  4096 
  4097 	DMMCSession& s = Session();
  4098 	OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM1, "Current session=0x%x", &s );
  4099 
  4100 	SMF_BEGIN
  4101 		//
  4102 		// Start the BUSTEST sequence at the maximum supported by the PSL
  4103 		//  - iSpare[0] keeps track of the current bus width
  4104 		//
  4105 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM2, "EStBegin" );
  4106 		if (iBusWidthAndClock & E8BitMask)
  4107 			{
  4108 			iSpare[0] = EBusWidth8;
  4109 			__KTRACE_OPT(KPBUS1, Kern::Printf("...Hardware supports 8-bit bus"));
  4110 			OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM3, "Hardware supports 8-bit bus" );
  4111 			}
  4112 		else if(iBusWidthAndClock & E4BitMask)
  4113 			{
  4114 			iSpare[0] = EBusWidth4;
  4115 			__KTRACE_OPT(KPBUS1, Kern::Printf("...Hardware supports 4-bit bus"));
  4116 			OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM4, "Hardware supports 4-bit bus" );
  4117 			}
  4118 		else
  4119 			{
  4120 			__KTRACE_OPT(KPBUS1, Kern::Printf("...Hardware supports 1-bit bus"));
  4121 			OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM5, "Hardware supports 1-bit bus" );
  4122 			iSpare[0] = EBusWidth1;
  4123 			}
  4124 
  4125 		// remove KMMCModeCardControlled so that IssueCommandCheckResponseSMST doesn't try to 
  4126 		// override the bus width & clock rate using the card settings
  4127 		iConfig.RemoveMode( KMMCModeCardControlled );
  4128 
  4129 	SMF_STATE(EstSendBusTest_W)
  4130 		//
  4131 		// Issue the BUSTEST_W command
  4132 		//
  4133 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM6, "EStSendBusTest_W" );
  4134 		TInt length = 2;
  4135 		switch(iSpare[0])
  4136 			{
  4137 			case EBusWidth8:
  4138 				// Set the host to 8-bit mode
  4139 				__KTRACE_OPT(KPBUS1, Kern::Printf("BUSTEST : EBusWidth8"));
  4140 				OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM7, "BUSTEST : EBusWidth8" );
  4141 				DoSetBusWidth(EBusWidth8);
  4142 				iPSLBuf[0] = 0x55;
  4143 				iPSLBuf[1] = 0xaa;
  4144 				break;
  4145 
  4146 			case EBusWidth4:
  4147 				// Set the host to 4-bit mode
  4148 				__KTRACE_OPT(KPBUS1, Kern::Printf("BUSTEST : EBusWidth4"));
  4149 				OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM8, "BUSTEST : EBusWidth4" );
  4150 				DoSetBusWidth(EBusWidth4);
  4151 				iPSLBuf[0] = 0x5a;
  4152 				iPSLBuf[1] = 0x00;
  4153 				break;
  4154 
  4155 			case EBusWidth1:
  4156 			default:
  4157 				// Set the host to 1-bit mode
  4158 				__KTRACE_OPT(KPBUS1, Kern::Printf("BUSTEST : EBusWidth1"));
  4159 				OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM9, "BUSTEST : EBusWidth1" );
  4160 				DoSetBusWidth(EBusWidth1);
  4161 				iPSLBuf[0] = 0x40;
  4162 				iPSLBuf[1] = 0x00;
  4163 				break;
  4164 			}	
  4165 
  4166 		// Issue BUSTEST_W
  4167 
  4168 		__KTRACE_OPT(KPBUS1, Kern::Printf("...Issue BUSTEST_W [%02x:%02x]", iPSLBuf[1], iPSLBuf[0]));
  4169 		OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM10, "Issue BUSTEST_W [%02x:%02x]", (TUint) iPSLBuf[1], (TUint) iPSLBuf[0] );
  4170 
  4171 		m.SetTraps(KMMCErrDataCRC); // CRC check is optional for BUSTEST
  4172 
  4173 		s.FillCommandDesc(ECmdBustest_W);
  4174 		s.FillCommandArgs(0, length, &iPSLBuf[0], length);
  4175 		SMF_INVOKES(IssueCommandCheckResponseSMST, EstSendBusTest_R)
  4176 
  4177 	SMF_STATE(EstSendBusTest_R)
  4178 		//
  4179 		// Issue the BUSTEST_R command
  4180 		//
  4181 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM11, "EStSendBusTest_R" );
  4182 		__KTRACE_OPT(KPBUS1, Kern::Printf("...got BUSTEST_W response : %02x", err));
  4183 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM12, "Got BUSTEST_W response=0x%02x", err );
  4184 
  4185 		if(err == KMMCErrNone || err == KMMCErrDataCRC)
  4186 			{
  4187 			__KTRACE_OPT(KPBUS1, Kern::Printf("...sending BUSTEST_R"));
  4188 			OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM13, "Sending BUSTEST_R" );
  4189 
  4190 			iPSLBuf[0] = 0;
  4191 			iPSLBuf[1] = 0;
  4192 
  4193 			s.FillCommandDesc(ECmdBustest_R);
  4194 			s.FillCommandArgs(0, 2, &iPSLBuf[0], 2);
  4195 			SMF_INVOKES(IssueCommandCheckResponseSMST, EstGotBusTest_R)
  4196 			}
  4197 		else
  4198 			{
  4199 			OstTraceFunctionExitExt( DMMCSTACK_EXECBUSTESTSM_EXIT, this, (TInt) KMMCErrNotSupported );
  4200 			SMF_RETURN(KMMCErrNotSupported);
  4201 			}
  4202 
  4203 	SMF_STATE(EstGotBusTest_R)
  4204 		//
  4205 		// Validate the BUSTEST_R data with that issued by BUSTEST_W
  4206 		//
  4207 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM14, "EStGotBusTest_R" );
  4208 		__KTRACE_OPT(KPBUS1, Kern::Printf("...got BUSTEST_R response [%02x:%02x] : err(%02x)", iPSLBuf[1], iPSLBuf[0], err));
  4209 		OstTraceExt3( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM15, "Got BUSTEST_R response [%02x:%02x]; err(%x)", (TUint) iPSLBuf[1], (TUint) iPSLBuf[0], (TUint) err );
  4210 
  4211 		TBool retry = EFalse;
  4212 		TBool is52MHzSupported = (iBusWidthAndClock & E52MhzMask) ? (TBool)ETrue : (TBool)EFalse;
  4213 
  4214 		switch(iSpare[0])
  4215 			{
  4216 			case EBusWidth8:
  4217 				{
  4218 				if(iPSLBuf[0] == 0xAA && iPSLBuf[1] == 0x55)
  4219 					{
  4220 					// 8-Bit bus supported
  4221 					iBusWidthAndClock = is52MHzSupported ? E8Bits52Mhz : E8Bits26Mhz;
  4222 					}
  4223 				else
  4224 					{
  4225 					// 8-Bit bus not supported - retry with 4-Bit
  4226 					retry = ETrue;
  4227 					iSpare[0] = EBusWidth4;
  4228 					}
  4229 				break;
  4230 				}
  4231 
  4232 			case EBusWidth4:
  4233 				{
  4234 				if(iPSLBuf[0] == 0xA5)
  4235 					{
  4236 					// 4-Bit Bus Supported
  4237 					iBusWidthAndClock = is52MHzSupported ? E4Bits52Mhz : E4Bits26Mhz;
  4238 					}
  4239 				else
  4240 					{
  4241 					// 4-Bit bus not supported - retry with 1-Bit
  4242 					retry = ETrue;
  4243 					iSpare[0] = EBusWidth1;
  4244 					}
  4245 				break;
  4246 				}
  4247 
  4248 			case EBusWidth1:
  4249 				{
  4250 				if((iPSLBuf[0] & 0xC0) == 0x80)
  4251 					{
  4252 					// 1-Bit Bus Supported
  4253 					iBusWidthAndClock = E1Bit20Mhz;
  4254 					}
  4255 
  4256 				// Failed to perform BUSTEST with 1-Bit bus.
  4257 				//  - We can't recover from this, but let's continue using low-speed 1-Bit mode
  4258 				iBusWidthAndClock = E1Bit20Mhz;
  4259 				break;
  4260 				}
  4261 
  4262 			default:
  4263 				DMMCSocket::Panic(DMMCSocket::EMMCBadBusWidth);
  4264 				break;
  4265 			}	
  4266 
  4267 		if(retry)
  4268 			{
  4269 			__KTRACE_OPT(KPBUS1, Kern::Printf("...BUSTEST Failed : Retry"));
  4270 			OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM16, "BUSTEST Failed : Retry" );
  4271 			SMF_GOTOS(EstSendBusTest_W);
  4272 			}
  4273 		
  4274 		switch(iBusWidthAndClock)
  4275 			{
  4276 			case E1Bit20Mhz:
  4277 				iCardArray->CardP(iSelectedCardIndex)->SetBusWidth(1);
  4278 				break;
  4279 
  4280 			case E4Bits26Mhz:
  4281 			case E4Bits52Mhz:
  4282 				iCardArray->CardP(iSelectedCardIndex)->SetBusWidth(4);
  4283 				break;
  4284 
  4285 			case E8Bits26Mhz:
  4286 			case E8Bits52Mhz:
  4287 				iCardArray->CardP(iSelectedCardIndex)->SetBusWidth(8);
  4288 				break;
  4289 			}
  4290 
  4291 		__KTRACE_OPT(KPBUS1, Kern::Printf("...BUSTEST OK"));
  4292 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM17, "BUSTEST OK" );
  4293 
  4294 		DoSetBusWidth(EBusWidth1);
  4295 
  4296 	SMF_STATE(EStExit)
  4297 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM18, "EStExit" );
  4298 		iConfig.SetMode( KMMCModeCardControlled );
  4299 
  4300 	SMF_END
  4301 	}
  4302 
  4303 
  4304 /**
  4305  * PSL-supplied method to retrieve an interface.
  4306  * The caller should set aInterfacePtr to NULL before calling
  4307  * the PSL should only modify aInterfacePtr if it supports the interface
  4308  * The default implementation here does nothing
  4309  * Replaces Dummy2()
  4310 */
  4311 EXPORT_C void DMMCStack::GetInterface(TInterfaceId aInterfaceId, MInterface*& aInterfacePtr)
  4312 	{
  4313 	OstTraceFunctionEntry1( DMMCSTACK_GETINTERFACE_ENTRY, this );
  4314 	if (aInterfaceId == KInterfaceCancelSession)
  4315 		{
  4316 		DMMCSession* session = (DMMCSession*&) aInterfacePtr;
  4317 		Abort(session);
  4318 		UnlockStack(session);
  4319 		}
  4320 
  4321 	OstTraceFunctionExit1( DMMCSTACK_GETINTERFACE_EXIT, this );
  4322 	}
  4323 
  4324 
  4325 TMMCErr DMMCStack::GoIdleSM()
  4326 /**
  4327  * Issues GO_IDLE_STATE twice with a RetryGap between them. 
  4328  * After that the bus context ought to be considered as "known".
  4329  * @return MMC error code
  4330  */
  4331 	{
  4332 		enum states
  4333 			{
  4334 			EStBegin=0,
  4335 			EStIdleLoop,
  4336 			EStIdleEndCheck,
  4337 			EStEnd
  4338 			};
  4339 
  4340 		DMMCSession& s=Session();
  4341 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_GOIDLESM1, "Current session=0x%x", &s );
  4342 
  4343 	SMF_BEGIN
  4344 
  4345 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_GOIDLESM2, "EStBegin" );
  4346 		s.FillCommandDesc( ECmdGoIdleState, 0 );
  4347 		iCxPollRetryCount = KMMCIdleCommandsAtRestart;
  4348 
  4349 	SMF_STATE(EStIdleLoop)
  4350 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_GOIDLESM3, "EStIdleLoop" );
  4351 		SMF_INVOKES( ExecCommandSMST, EStIdleEndCheck )
  4352 
  4353 	SMF_STATE(EStIdleEndCheck)
  4354 
  4355 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_GOIDLESM4, "EStIdleEndCheck" );
  4356 		if( --iCxPollRetryCount > 0 )
  4357 			SMF_INVOKES( RetryGapTimerSMST, EStIdleLoop )
  4358 
  4359 		iStackState &= ~(KMMCStackStateDoDeselect|KMMCStackStateBusInconsistent);
  4360 		iSelectedCard = 0;
  4361 
  4362 		// According to the spec, the default bus width after power up or GO_IDLE is 1 bit bus width
  4363 		DoSetBusWidth(EBusWidth1);
  4364 
  4365 	SMF_END
  4366 	}
  4367 
  4368 EXPORT_C TMMCErr DMMCStack::AcquireStackSM()
  4369 /**
  4370  * This macro acquires new cards in an MMC - bus topology stack.
  4371  * It starts with the Controller reading the operating conditions of the 
  4372  * cards in the stack (SEND_OP_COND - CMD1). Then, any new cards in the stack
  4373  * are identified (ALL_SEND_CID - CMD2) and each one is assigned a relative
  4374  * card address (SET_RCA - CMD3). This is done by systematically broadcasting
  4375  * CMD2 to all cards on the bus until all uninitialized cards have responded.
  4376  * Finally the card specific data (SEND_CSD - CMD9) is read from each card.
  4377  * @return MMC error code
  4378  */
  4379 	{
  4380 		enum states
  4381 			{
  4382 			EStBegin=0,
  4383 			EStIdle,
  4384 			EStFullRangeDone,
  4385 			EStSetRangeLoop,
  4386 			EStSetRangeBusyCheck,
  4387 			EStCIDLoop,
  4388 			EStSendCIDIssued,
  4389 			EStCIDsDone,
  4390 			EStCSDLoop,
  4391 			EStSendCSDDone,
  4392 			EStMergeCards,
  4393 			EStReMergeCards,
  4394 			EStEnd
  4395 			};
  4396 
  4397 		DMMCSession& s=Session();
  4398 		DMMCPsu* psu=(DMMCPsu*)iSocket->iVcc;
  4399 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM1, "Current session=0x%x", &s );
  4400 
  4401 	SMF_BEGIN
  4402 
  4403 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM2, "EStBegin" );
  4404 		iRCAPool.ReleaseUnlocked();
  4405 		iCxPollRetryCount = 0; // Reset max number of poll attempts on card busy
  4406 
  4407 		SMF_INVOKES( GoIdleSMST, EStIdle )
  4408 
  4409 	SMF_STATE(EStIdle)
  4410 
  4411 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM3, "EStIdle" );
  4412 		// If this platform doesn't support an adjustable voltage PSU then there is
  4413 		// no point in interogating the card(s) present for their supported range
  4414 		if ( !(psu->VoltageSupported()&KMMCAdjustableOpVoltage) )
  4415 			{
  4416 			// if the PSU isn't adjustable then it can't support low voltage mode
  4417 			iCurrentOpRange&= ~KMMCOCRLowVoltage;
  4418 			s.FillCommandDesc(ECmdSendOpCond, (iCurrentOpRange | KMMCOCRAccessModeHCS | KMMCOCRBusy));	// Range supported + Busy bit (iArgument==KBit31)
  4419 			SMF_GOTOS( EStSetRangeLoop )
  4420 			}
  4421 
  4422 		// Interrogate card(s) present - issue CMD1 with omitted voltage range
  4423 		s.FillCommandDesc( ECmdSendOpCond, KMMCOCRAccessModeHCS | KMMCOCRBusy);	// Full range + Sector Access + Busy bit (iArgument==KBit31)
  4424 		m.SetTraps( KMMCErrResponseTimeOut );
  4425 
  4426 		SMF_INVOKES( ExecCommandSMST, EStFullRangeDone )
  4427 
  4428 	SMF_STATE(EStFullRangeDone)
  4429 
  4430 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM4, "EStFullRangeDone" );
  4431 		if( err )												// If timeout
  4432 			{
  4433 			iConfig.RemoveMode( KMMCModeEnableTimeOutRetry );	// There is no point to do it second time
  4434 			}
  4435 		else
  4436 			{
  4437 			// Cards responded with Op range - evaluate the common subset with the current setting
  4438 			// Dont worry aboout the busy bit for now, we'll check that when we repeat the command
  4439 			TUint32 newrange = (TMMC::BigEndian32(s.ResponseP()) & ~KMMCOCRBusy);
  4440 			newrange &= iCurrentOpRange;
  4441 
  4442 			if (newrange==0)
  4443 				{
  4444 				// One or more card is incompatible with our h/w
  4445 				if (iMaxCardsInStack<=1)
  4446 				    {
  4447 					OstTraceFunctionExitExt( DMMCSTACK_ACQUIRESTACKSM_EXIT1, this, (TInt) KMMCErrNotSupported );
  4448 					return KMMCErrNotSupported; // There can only be one card - we don't support it.
  4449 				    }
  4450 				else
  4451 					// Force the default range
  4452 					iCurrentOpRange=(psu->VoltageSupported() & ~KMMCAdjustableOpVoltage);  
  4453 				}
  4454 			else
  4455 				iCurrentOpRange=newrange;		// OK, new cards are compatible
  4456 			}
  4457 
  4458 		// If platform and the card both support low voltage mode (1.65 - 1.95v), switch
  4459 		if (iCurrentOpRange & KMMCOCRLowVoltage)
  4460 			{
  4461 			iCurrentOpRange = KMMCOCRLowVoltage;
  4462 			SMF_INVOKES( SwitchToLowVoltageSMST, EStSetRangeLoop )
  4463 			}
  4464 
  4465 	SMF_STATE(EStSetRangeLoop)
  4466 
  4467 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM5, "EStSetRangeLoop" );
  4468 		// Repeat CMD1 this time setting Current Op Range
  4469 		s.Command().iArgument = iCurrentOpRange | KMMCOCRAccessModeHCS | KMMCOCRBusy;
  4470 
  4471 		m.SetTraps( KMMCErrResponseTimeOut );
  4472 
  4473 		SMF_INVOKES( ExecCommandSMST, EStSetRangeBusyCheck )
  4474 
  4475 	SMF_STATE(EStSetRangeBusyCheck)
  4476 
  4477 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM6, "EStSetRangeLoop" );
  4478 		if( !err )
  4479 			{
  4480 			// Bit31 of the OCR response is low if the cards are still powering up.
  4481 			const TUint32 ocrResponse = TMMC::BigEndian32(s.ResponseP());
  4482 
  4483 			const TBool isBusy = ((ocrResponse & KMMCOCRBusy) == 0);
  4484 			__KTRACE_OPT(KPBUS1,Kern::Printf("-mmc:upd:bsy%d", isBusy));
  4485 			OstTrace1( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM7, "MMC busy status=%d", isBusy );
  4486 
  4487 			if (isBusy)	
  4488 				{
  4489 				// Some cards are still busy powering up. Check if we should timeout
  4490 				if ( ++iCxPollRetryCount > iConfig.OpCondBusyTimeout() )
  4491 				    {
  4492 					OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM8, "Peripheral bus timeout" );
  4493 					OstTraceFunctionExitExt( DMMCSTACK_ACQUIRESTACKSM_EXIT2, this, (TInt) KMMCErrBusTimeOut );
  4494 					return KMMCErrBusTimeOut;
  4495 				    }
  4496 				m.ResetTraps();
  4497 				SMF_INVOKES( RetryGapTimerSMST, EStSetRangeLoop )
  4498 				}
  4499 
  4500 			iSpare[0] = 0;
  4501 
  4502 			if((ocrResponse & KMMCOCRAccessModeMask) == KMMCOCRAccessModeHCS)
  4503 				{
  4504 				__KTRACE_OPT(KPBUS1, Kern::Printf("Found large MMC card."));
  4505 				OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM9, "Found large MMC card" );
  4506 				iSpare[0] = KMMCardIsHighCapacity;
  4507 				}
  4508 			}
  4509 
  4510 		iConfig.SetMode( EffectiveModes(s.iConfig) & KMMCModeEnableTimeOutRetry );	// Restore original setting
  4511 
  4512 		// All cards are now ready and notified of the voltage range - ask ASSP to set it up
  4513 		psu->SetVoltage(iCurrentOpRange);
  4514 		if (psu->SetState(EPsuOnFull) != KErrNone)
  4515 		    {
  4516 			OstTraceFunctionExitExt( DMMCSTACK_ACQUIRESTACKSM_EXIT3, this, (TInt) KMMCErrHardware );
  4517 			return KMMCErrHardware;
  4518 		    }
  4519 
  4520 		iCardArray->InitNewCardScan(); // Collect new cards, one by one
  4521 
  4522 	SMF_STATE(EStCIDLoop)
  4523 
  4524 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM10, "EStCIDLoop" );
  4525 		if ( iCardArray->NewCardCount() >= iMaxCardsInStack )
  4526 			SMF_GOTOS( EStCIDsDone )
  4527 
  4528 		s.FillCommandDesc( ECmdAllSendCID, 0 );
  4529 		m.SetTraps( KMMCErrResponseTimeOut );
  4530 
  4531 		SMF_INVOKES( ExecCommandSMST, EStSendCIDIssued )
  4532 
  4533 	SMF_STATE(EStSendCIDIssued)
  4534 
  4535 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM11, "EStSendCIDIssued" );
  4536 		if( !err )
  4537 			{
  4538 			// A card responded with a CID. Create a new card entry in the card array 
  4539 			// and initialise this entry with the CID. The card array allocates it an
  4540 			// RCA, either the old RCA if we have seen this card before, or a new one.
  4541 			TRCA rca;
  4542 			iCardArray->AddNewCard(s.ResponseP(),&rca); // Response is CID
  4543 
  4544 			// Now assign the new RCA to the card
  4545 			s.FillCommandDesc( ECmdSetRelativeAddr, TMMCArgument(rca) );
  4546 			m.ResetTraps();
  4547 			SMF_INVOKES( ExecCommandSMST, EStCIDLoop )
  4548 			}
  4549 
  4550 	SMF_STATE(EStCIDsDone)
  4551 
  4552 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM12, "EStCIDsDone" );
  4553 		// All cards are initialised; get all their CSDs
  4554 		m.ResetTraps();				// We are no longer processing any errors
  4555 
  4556 		if( iCardArray->NewCardCount()==0 )
  4557 			SMF_EXIT						// No new cards acquired
  4558 
  4559 		iCxCardCount=0;							// New cards index
  4560 		s.FillCommandDesc( ECmdSendCSD );
  4561 
  4562 	SMF_STATE(EStCSDLoop)
  4563 
  4564 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM13, "EStCSDLoop" );
  4565 		s.Command().iArgument = TMMCArgument(iCardArray->NewCardP(iCxCardCount)->iRCA);
  4566 		SMF_INVOKES( ExecCommandSMST, EStSendCSDDone )
  4567 
  4568 	SMF_STATE(EStSendCSDDone)
  4569 
  4570 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM14, "EStSendCSDDone" );
  4571 		// Store the CSD in the new card entry
  4572 		TMMCard* cardP = iCardArray->NewCardP(iCxCardCount);
  4573 		cardP->iCSD = s.ResponseP();
  4574 
  4575 		// Perform MMC Specific parsing of the CSD structure
  4576 		TUint specVers = cardP->CSD().SpecVers();	// 1 => 1.4, 2 => 2.0 - 2.2, 3 => 3.1
  4577 
  4578 		if ((specVers >= 2) && (cardP->CSD().CCC() & KMMCCmdClassLockCard))
  4579 			{
  4580 			cardP->iFlags |= KMMCardIsLockable;
  4581 			}
  4582 
  4583 		if(iSpare[0] == KMMCardIsHighCapacity)
  4584 			{
  4585 			cardP->iFlags |= KMMCardIsHighCapacity;
  4586 			}
  4587 
  4588 		if( ++iCxCardCount < (TInt)iCardArray->NewCardCount() )
  4589 			SMF_GOTOS( EStCSDLoop )
  4590 
  4591 		SMF_NEXTS(EStMergeCards)
  4592 
  4593 	SMF_STATE(EStMergeCards)
  4594 
  4595 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM15, "EStMergeCards" );
  4596 		// Merging the old card info with newly acquired cards (we will ask each card for status
  4597 		// to determine whether it's really present later).
  4598 		if( SchedGetOnDFC() )
  4599 			SMF_WAIT
  4600 		if ( iCardArray->MergeCards(ETrue)==KErrNone )
  4601 			SMF_EXIT						// Completed successfully
  4602 
  4603 		SMF_INVOKES( CheckStackSMST, EStReMergeCards ) // No space so check if any cards have gone
  4604 
  4605 	SMF_STATE(EStReMergeCards)
  4606 
  4607 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM16, "EStReMergeCards" );
  4608 		if( SchedGetOnDFC() )
  4609 			SMF_WAIT
  4610 		if ( iCardArray->MergeCards(EFalse)!=KErrNone ) // There are more cards in the stack than we can handle
  4611 		    {
  4612 			OstTraceFunctionExitExt( DMMCSTACK_ACQUIRESTACKSM_EXIT4, this, (TInt) KMMCErrTooManyCards );
  4613 			return KMMCErrTooManyCards;
  4614 		    }
  4615 
  4616 	SMF_END
  4617 	}
  4618 
  4619 
  4620 /**
  4621  * Power down the bus and power it up again in low-voltage mode
  4622  * 
  4623  * @return MMC error code.
  4624  */
  4625 TMMCErr DMMCStack::SwitchToLowVoltageSM()
  4626 	{
  4627 	enum states
  4628 		{
  4629 		EStBegin=0,
  4630 		EStPoweredUp,
  4631 		EStClockOn,
  4632 		EStEnd
  4633 		};
  4634 
  4635 	__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:SwLowVolt"));
  4636 
  4637 	DMMCPsu* psu=(DMMCPsu*)iSocket->iVcc;
  4638 	OstTrace1( TRACE_INTERNALS, DMMCSTACK_SWITCHTOLOWVOLTAGESM1, "Current PSU=0x%x", psu );
  4639 
  4640 	SMF_BEGIN
  4641 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_SWITCHTOLOWVOLTAGESM2, "EStBegin" );
  4642 		// turn power off
  4643 		DoPowerDown();
  4644 		psu->SetState(EPsuOff);
  4645 
  4646 		// turn power back on in low voltage mode
  4647 		psu->SetVoltage(iCurrentOpRange);
  4648 		if (psu->SetState(EPsuOnFull) != KErrNone)
  4649 		    {
  4650 			OstTraceFunctionExitExt( DMMCSTACK_SWITCHTOLOWVOLTAGESM_EXIT, this, (TInt) KMMCErrHardware );
  4651 			return KMMCErrHardware;
  4652 		    }
  4653 
  4654 		SMF_INVOKES( DoPowerUpSMST, EStPoweredUp )
  4655 
  4656 	SMF_STATE(EStPoweredUp)
  4657 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_SWITCHTOLOWVOLTAGESM3, "EStPoweredUp" );
  4658 		// turn the clock back on
  4659 		SMF_INVOKES( InitClockOnSMST, EStClockOn )	// Feed init clock to the bus
  4660 
  4661 	SMF_STATE(EStClockOn)
  4662 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_SWITCHTOLOWVOLTAGESM4, "EStClockOn" );
  4663 		// wait for 1ms and then 74 clock cycles
  4664 		// 74 clock cylces @ 400 Khz = 74 / 400,000 = 0.000185 secs = 0.185 ms
  4665 		// so total wait = 1.185 ms
  4666 		SMF_INVOKES(LowVoltagePowerupTimerSMST, EStEnd);
  4667 
  4668 	SMF_END
  4669 
  4670 	}
  4671 
  4672 inline TMMCErr DMMCStack::CIMCheckStackSM()
  4673 /**
  4674  * Performs the CIM_CHECK_STACK macro (with pre-emption disabled).
  4675  * @return MMC error code
  4676  */
  4677 	{
  4678 		enum states
  4679 			{
  4680 			EStBegin=0,
  4681 			EStFinish,
  4682 			EStEnd
  4683 			};
  4684 
  4685 		DMMCSession& s=Session();
  4686 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMCHECKSTACKSM1, "Current session=0x%x", &s );
  4687 
  4688 	SMF_BEGIN
  4689 
  4690 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMCHECKSTACKSM2, "EStBegin" );
  4691 		// This macro works naked and must not be preempted
  4692 		iConfig.RemoveMode( KMMCModeEnablePreemption | KMMCModeCardControlled );
  4693 		s.iState |= KMMCSessStateInProgress;
  4694 
  4695 		SMF_INVOKES( CheckStackSMST, EStFinish )
  4696 
  4697 	SMF_STATE(EStFinish)
  4698 
  4699 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMCHECKSTACKSM3, "EStFinish" );
  4700 		s.iState &= ~KMMCSessStateInProgress;
  4701 
  4702 	SMF_END
  4703 	}
  4704 
  4705 inline TMMCErr DMMCStack::CheckStackSM()
  4706 /**
  4707  * For each card in iCards[], sends CMD13 to see if still there.
  4708  * If not, calls DeclareCardAsGone().  Frees up space for new cards.
  4709  * @return MMC error code
  4710  */
  4711 	{
  4712 		enum states
  4713 			{
  4714 			EStBegin=0,
  4715 			EStLoop,
  4716 			EStCardSelectedGotStatus,
  4717 			EStCardDeselected,
  4718 			EStEnd
  4719 			};
  4720 
  4721 		DMMCSession& s=Session();
  4722 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM1, "Current session=0x%x", &s );
  4723 
  4724 	SMF_BEGIN
  4725 
  4726 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM2, "EStBegin" );
  4727 		iCxCardCount=-1;
  4728 		m.SetTraps( KMMCErrResponseTimeOut );
  4729 
  4730 	SMF_STATE(EStLoop)
  4731 
  4732 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM3, "EStLoop" );
  4733 		if ( ++iCxCardCount == (TInt)iMaxCardsInStack )
  4734 			SMF_EXIT
  4735 
  4736 		if ( !iCardArray->CardP(iCxCardCount)->IsPresent() )
  4737 			SMF_GOTOS( EStLoop )					// card's not present
  4738 
  4739 		TUint32 arg = TUint32(iCardArray->CardP(iCxCardCount)->RCA()) << 16;
  4740 		s.FillCommandDesc(ECmdSelectCard, arg);
  4741 		SMF_INVOKES(ExecCommandSMST, EStCardSelectedGotStatus)
  4742 
  4743 	SMF_STATE(EStCardSelectedGotStatus)
  4744 
  4745 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM4, "EStCardSelectedGotStatus" );
  4746 		__KTRACE_OPT(KPBUS1, Kern::Printf("-mst:cssm:err%08x", err));
  4747 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM5, "err=0x%08x", err );
  4748 
  4749 		if(err)
  4750 			{
  4751 			// Timeout - the card is no longer present so remove from the card array
  4752 			iCardArray->DeclareCardAsGone(iCxCardCount);
  4753 			SMF_GOTOS( EStLoop )
  4754 			}
  4755 
  4756 		TMMCard& card=*(iCardArray->CardP(iCxCardCount));
  4757 		card.iStatus=s.ResponseP();
  4758 
  4759 		// This function is only called as part of the power up sequence, so
  4760 		// take the opportunity to record if it has a password
  4761 		if((card.iStatus & KMMCStatCardIsLocked) != 0)
  4762 			{
  4763 			card.iFlags|=KMMCardHasPassword;
  4764 			}
  4765 
  4766 		s.FillCommandDesc(ECmdSelectCard, 0);
  4767 		SMF_INVOKES(ExecCommandSMST, EStCardDeselected)
  4768 			
  4769 	SMF_STATE(EStCardDeselected)
  4770 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM6, "EStCardDeselected" );
  4771 		SMF_GOTOS( EStLoop )
  4772 
  4773 	SMF_END
  4774 	}
  4775 
  4776 inline TMMCErr DMMCStack::CheckLockStatusSM()
  4777 /*
  4778  * Called as part of the power-up sequence, this determined if the card is locked or has a password.
  4779  *
  4780  * If the card reports itself as being unlocked and there is a mapping in the password store, 
  4781  * then the stored password is used to attempt to lock the card. The overall aim of this is
  4782  * to ensure that if a card always powers up in the locked state if it contains a known password.
  4783  *
  4784  * This ensures that cards that are still unlocked after a power down/power up sequence do not
  4785  * end up having their passwords removed from the store, which can happen in environments where
  4786  * the PSU voltage level is not monitored - in such systems, we cannot guarantee that a card will 
  4787  * be fully reset and power up locked, hence the need to attempt to lock the card.
  4788  *
  4789  * @return MMC error code
  4790  */
  4791 	{
  4792 		enum states
  4793 			{
  4794 			EStBegin=0,
  4795 			EStLoop,
  4796 			EStCardSelectedGotStatus,
  4797 			EStCheckLockStatus,
  4798 			EStCardDeselected,
  4799 			EStEnd
  4800 			};
  4801 
  4802 		DMMCSession& s=Session();
  4803 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM1, "Current session=0x%x", &s );
  4804 
  4805 	SMF_BEGIN
  4806 
  4807 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM2, "EStBegin" );
  4808 		iCxCardCount=-1;
  4809 		m.SetTraps( KMMCErrResponseTimeOut );
  4810 		iMinorBufLen = KMinMinorBufSize;
  4811 
  4812 	SMF_STATE(EStLoop)
  4813 
  4814 		if ( ++iCxCardCount == (TInt)iMaxCardsInStack )
  4815 			SMF_EXIT
  4816 
  4817 		if ( !iCardArray->CardP(iCxCardCount)->IsPresent() )
  4818 			SMF_GOTOS( EStLoop )					// card's not present
  4819 
  4820 		TUint32 arg = TUint32(iCardArray->CardP(iCxCardCount)->RCA()) << 16;
  4821 		s.FillCommandDesc(ECmdSelectCard, arg);
  4822 		SMF_INVOKES(ExecCommandSMST, EStCardSelectedGotStatus)
  4823 
  4824 	SMF_STATE(EStCardSelectedGotStatus)
  4825 
  4826 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM3, "EStCardSelectedGotStatus" );
  4827 		__KTRACE_OPT(KPBUS1, Kern::Printf("-mst:cssm:err%08x", err));
  4828 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM4, "err=0x%08x", err );
  4829 		if ( !err )
  4830 			{
  4831 			TMMCard& card=*(iCardArray->CardP(iCxCardCount));
  4832 			card.iStatus=s.ResponseP(); // Got the response
  4833 
  4834 			iMinorBufLen = Max(iMinorBufLen, 1 << card.MaxReadBlLen());
  4835 
  4836 			// this function is only called as part of the power up sequence, so
  4837 			// take the opportunity to record if it has a password
  4838 			if((card.iStatus & KMMCStatCardIsLocked) != 0)
  4839 				{
  4840 				card.iFlags |= KMMCardHasPassword;
  4841 				}
  4842 				
  4843 			// If the status suggests that the card is unlocked, we test
  4844 			// for the presence of a password by attempting to lock the card
  4845 			// (if we have a password in the store).  This handles conditions
  4846 			// where a card has not been fully powered down before reapplying power.
  4847 			if(!(card.iFlags & KMMCardHasPassword))
  4848 				{
  4849 				TMapping* pmp = iSocket->iPasswordStore->FindMappingInStore(card.CID());
  4850 				if(pmp)
  4851 					{
  4852 					if(pmp->iState == TMapping::EStValid)
  4853 						{
  4854 						const TInt kPWD_LEN = pmp->iPWD.Length();
  4855 						iPSLBuf[0] = KMMCLockUnlockLockUnlock;	// LOCK_UNLOCK = 1, SET_PWD = 0, CLR_PWD = 0
  4856 						iPSLBuf[1] = static_cast<TUint8>(kPWD_LEN);
  4857 						TPtr8 pwd(&iPSLBuf[2], kPWD_LEN);
  4858 						pwd.Copy(pmp->iPWD);
  4859 
  4860 						const TInt kBlockLen = 1 + 1 + kPWD_LEN;
  4861 
  4862 						// Need to use CIMReadWriteBlocksSMST to ensure that the
  4863 						// card is connected and the block length is set correctly
  4864 						s.SetCard(iCardArray->CardP(iCxCardCount));
  4865 						m.SetTraps(KMMCErrStatus | KMMCErrUpdPswd);
  4866 						s.FillCommandDesc(ECmdLockUnlock);
  4867 						s.FillCommandArgs(0, kBlockLen, iPSLBuf, kBlockLen);
  4868 
  4869 						TMMCCommandDesc& cmd = s.Command();
  4870 						cmd.iUnlockRetries = 0;
  4871 						
  4872 						SMF_INVOKES(CIMReadWriteBlocksSMST,EStCheckLockStatus)
  4873 						}
  4874 					}
  4875 				}
  4876 			}
  4877 
  4878 		SMF_GOTOS( EStLoop )
  4879 
  4880 	SMF_STATE(EStCheckLockStatus)
  4881 
  4882 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM5, "EStCheckLockStatus" );
  4883 		__KTRACE_OPT(KPBUS1, Kern::Printf("-mst:cssm:err%08x", err));
  4884 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM6, "err=0x%08x", err );
  4885 
  4886 		if ((err & KMMCErrUpdPswd) || 
  4887 		   ((err & KMMCErrStatus) && (s.LastStatus().Error() == KMMCStatErrLockUnlock)))
  4888 			{
  4889 			// ECMDLockUnlock (with LockUnlockLockUnlock param) succeeded.
  4890 			// (either locked successfully, or we have attempted to lock a locked card)
  4891 			// Now determine if the card really is locked by checking the lock status.
  4892 			TMMCard& card=*(iCardArray->CardP(iCxCardCount));
  4893 			card.iStatus=s.LastStatus();
  4894 			if((card.iStatus & KMMCStatCardIsLocked) != 0)
  4895 				{
  4896 				card.iFlags |= KMMCardHasPassword;
  4897 				}
  4898 			}
  4899 
  4900 		s.FillCommandDesc(ECmdSelectCard, 0);
  4901 		SMF_INVOKES(ExecCommandSMST, EStCardDeselected)
  4902 			
  4903 	SMF_STATE(EStCardDeselected)
  4904 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM7, "EStCardDeselected" );
  4905 		SMF_GOTOS( EStLoop )
  4906 
  4907 	SMF_END
  4908 	}
  4909 
  4910 EXPORT_C TMMCErr DMMCStack::ModifyCardCapabilitySM()
  4911 //
  4912 // This function provides a chance to modify the capability of paticular cards.
  4913 // Licensee may overide this function to modify certain card's capability as needed.
  4914 // A state machine is needed in derived function and function of base class should be
  4915 // called in order to act more generic behaviour.
  4916 //
  4917     {
  4918 		enum states
  4919 			{
  4920 			EStBegin=0,
  4921 			EStEnd
  4922 			};
  4923 
  4924     SMF_BEGIN
  4925 
  4926     SMF_END
  4927     }
  4928 
  4929 //
  4930 // Timers
  4931 //
  4932 
  4933 inline TMMCErr DMMCStack::PollGapTimerSM()
  4934 /**
  4935  * Starts the poll timer.
  4936  *
  4937  * This may be used when executing CIM_UPDATE_ACQ when handling cards which are 
  4938  * slow to power-up/reset and return busy following the issuing of CMD1.
  4939  *
  4940  * @return MMC error code.
  4941  */
  4942 	{
  4943 		enum states
  4944 			{
  4945 			EStBegin=0,
  4946 			EStEnd
  4947 			};
  4948 #ifdef __EPOC32__
  4949 		DMMCSession& s=Session();
  4950 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_POLLGAPTIMERSM1, "Current session=0x%x", &s );
  4951 #endif
  4952 
  4953 	SMF_BEGIN
  4954 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_POLLGAPTIMERSM2, "EStBegin" );
  4955 #ifdef __EPOC32__
  4956 		s.SynchBlock( KMMCBlockOnPollTimer );
  4957 		s.iPollTimer.OneShot(KMMCPollGapInMilliseconds,EFalse);
  4958 
  4959 		SMF_EXITWAIT
  4960 #endif
  4961 
  4962 	SMF_END
  4963 	}
  4964 
  4965 inline TMMCErr DMMCStack::RetryGapTimerSM()
  4966 /**
  4967  * Starts the retry timer. 
  4968  *
  4969  * This may be used when executing CIM_UPDATE_ACQ. When initialising the stack,
  4970  * CMD0 is issued twice to get the bus in a known state and this timer is used 
  4971  * to time the gap between issuing the two CMD0 commands.
  4972  *
  4973  * @return MMC error code.
  4974  */
  4975 	{
  4976 		enum states
  4977 			{
  4978 			EStBegin=0,
  4979 			EStEnd
  4980 			};
  4981 #ifdef __EPOC32__
  4982 		DMMCSession& s=Session();
  4983 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_RETRYGAPTIMERSM1, "Current session=0x%x", &s );
  4984 #endif
  4985 
  4986 	SMF_BEGIN
  4987 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_RETRYGAPTIMERSM2, "EStBegin" );
  4988 #ifdef __EPOC32__
  4989 		s.SynchBlock( KMMCBlockOnRetryTimer );
  4990 		s.iRetryTimer.OneShot(KMMCRetryGapInMilliseconds,EFalse);
  4991 
  4992 		SMF_EXITWAIT
  4993 #endif
  4994 
  4995 	SMF_END
  4996 	}
  4997 
  4998 inline TMMCErr DMMCStack::ProgramTimerSM()
  4999 /**
  5000  * Starts the program timer.
  5001  *
  5002  * This is used during write operartions to a card to sleep for an PSL-dependent period 
  5003  * between issuing send status commands (CMD13). This is required in order to check when 
  5004  * the card has finished writing its data to payload memory.
  5005  *
  5006  * @return MMC error code.
  5007  */
  5008 	{
  5009 	enum states
  5010 		{
  5011 		EStBegin = 0,
  5012 		EStEnd
  5013 		};
  5014 
  5015 #ifdef __EPOC32__
  5016 	DMMCSession &s = Session();
  5017 	OstTrace1( TRACE_INTERNALS, DMMCSTACK_PROGRAMTIMERSM1, "Current session=0x%x", &s );
  5018 #endif
  5019 
  5020 	SMF_BEGIN
  5021 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_PROGRAMTIMERSM2, "EStBegin" );
  5022 #ifdef __EPOC32__
  5023 		s.SynchBlock(KMMCBlockOnPgmTimer);
  5024 		s.iProgramTimer.Cancel();
  5025 		s.iProgramTimer.OneShot(ProgramPeriodInMilliSeconds(),EFalse);
  5026 
  5027 		SMF_EXITWAIT
  5028 #endif
  5029 	SMF_END
  5030 	}
  5031 
  5032 TMMCErr DMMCStack::LowVoltagePowerupTimerSM()
  5033 /**
  5034  * Starts the low voltage power-up timer
  5035  * NB Re-uses the retry gap timer.
  5036  *
  5037  * This is used after powering the bus off and then on after discovering that 
  5038  * both the controller and card support low voltage operation.
  5039  *
  5040  * @return MMC error code.
  5041  */
  5042 	{
  5043 	enum states
  5044 		{
  5045 		EStBegin = 0,
  5046 		EStEnd
  5047 		};
  5048 
  5049 #ifdef __EPOC32__
  5050 	DMMCSession &s = Session();
  5051 	OstTrace1( TRACE_INTERNALS, DMMCSTACK_LOWVOLTAGEPOWERUPTIMERSM1, "Current session=0x%x", &s );
  5052 #endif
  5053 
  5054 	SMF_BEGIN
  5055 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_LOWVOLTAGEPOWERUPTIMERSM2, "EStBegin" );
  5056 #ifdef __EPOC32__
  5057 		s.SynchBlock(KMMCBlockOnRetryTimer);
  5058 		s.iRetryTimer.OneShot(KMMCLowVoltagePowerUpTimeoutInMilliseconds,EFalse);
  5059 
  5060 		SMF_EXITWAIT
  5061 #endif
  5062 	SMF_END
  5063 	}
  5064 
  5065 
  5066 inline TMMCErr DMMCStack::ExecCommandSM()
  5067 /**
  5068  * The main command executor. 
  5069  * Depending on the main command being issued, this macro may result in the issuing of whole sequence 
  5070  * of commands as it prepares the bus for the command in question. 
  5071  *
  5072  * In certain circumstances, this first issues one or more de-select commands (CMD7 + reserved RCA) 
  5073  * to get the bus in a known state. It then analyses the main command and if necessary, selects the 
  5074  * card in question (CMD7 + target RCA). 
  5075  *
  5076  * For block transfer commands, it will set the block length on the card concerned (CMD16) if this has 
  5077  * not been done already. Likewise, for SD Cards, if the bus width has not yet been set-up, it will issue 
  5078  * the appropriate bus width command (ACMD6). 
  5079  * 
  5080  * Finally it issues the main command requested before performing any error recovery that may be necessary 
  5081  * following this. 
  5082  *
  5083  * In all cases it calls the generic layer child function IssueCommandCheckResponseSM() to execute each command.
  5084  *
  5085  * @return MMC error code
  5086  */
  5087 	{
  5088 		enum states
  5089 			{
  5090 			EStBegin=0,
  5091 			EStExecCmd,
  5092 			EStRetry,
  5093 			EStDeselectLoop,
  5094 			EStDeselectEndCheck,
  5095 			EStAnalyseCommand,
  5096 			EStSelectDone,
  5097 			EStBlockCountCmdIssued,
  5098 			EStTestAppCommand,
  5099 			EStIssueAppCommandDone,
  5100 			EStIssueCommand,
  5101 			EStCommandIssued,
  5102 			EStErrRecover,
  5103 			EStEnd
  5104 			};
  5105 
  5106 		DMMCSession& s=Session();
  5107 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM1, "Current session=0x%x", &s );
  5108 		
  5109 	SMF_BEGIN
  5110 
  5111 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM2, "EStBegin" );
  5112 		if ( ( s.CardRCA() != 0 ) && ( (s.CardP()->iStatus.State()) == ECardStateSlp) )
  5113 			{
  5114 			// Currently selected media is asleep, so it must be awoken
  5115 			SMF_INVOKES(ExecAwakeCommandSMST,EStExecCmd)
  5116 			}
  5117 	
  5118 	SMF_STATE(EStExecCmd)
  5119 	
  5120 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM3, "EStExecCmd" );
  5121 		TMMCCommandDesc& cmd = s.Command();
  5122 		// clearup some internally used flags
  5123 		cmd.iFlags &= ~(KMMCCmdFlagExecTopBusy|KMMCCmdFlagExecSelBusy);
  5124 		cmd.iPollAttempts = cmd.iTimeOutRetries = cmd.iCRCRetries = 0;
  5125 
  5126 	SMF_STATE(EStRetry)
  5127 
  5128 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM4, "EStRetry" );
  5129 		TMMCCommandDesc& cmd = s.Command();
  5130 		m.SetTraps( KMMCErrBasic & ~Command().iExecNotHandle);	// Processing all trappable errors
  5131 
  5132 		if (iMultiplexedBus)
  5133 			{
  5134 			if(cmd.iCommand == ECmdSelectCard)
  5135 				{
  5136 				DeselectsToIssue(1);
  5137 				}
  5138 
  5139 			if (iConfig.iModes & KMMCModeCardControlled)
  5140 				{
  5141 				DoSetBusWidth(BusWidthEncoding(s.CardP()->BusWidth()));
  5142 				DoSetClock(MaxTranSpeedInKilohertz(*s.CardP()));
  5143 
  5144 				// Check if this card is already in the appropriate selected/deselected
  5145 				// state for the forthcoming command.
  5146 				if (s.CardRCA() != iSelectedCard)
  5147 					{
  5148 					DeselectsToIssue(1);
  5149 					}
  5150 				}
  5151 			}
  5152 
  5153 		// If bus context is unknown, issue DESELECT a few times with a RetryGap between them.
  5154 		if ( (iStackState & KMMCStackStateDoDeselect) == 0 )
  5155 			SMF_GOTOS( EStAnalyseCommand )
  5156 
  5157 		// Save the top-level command while we issue de-selects
  5158 		s.PushCommandStack();
  5159 		s.FillCommandDesc( ECmdSelectCard, 0 );		// Deselect - RCA=0
  5160 		iCxDeselectCount=iDeselectsToIssue;
  5161 
  5162 	SMF_STATE(EStDeselectLoop)
  5163 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM5, "EStDeselectLoop" );
  5164 		SMF_INVOKES(IssueCommandCheckResponseSMST,EStDeselectEndCheck)	
  5165 
  5166 	SMF_STATE(EStDeselectEndCheck)
  5167 
  5168 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM6, "EStDeselectEndCheck" );
  5169 		// If we got an error and this is the last de-select then give up
  5170 		if (err && iCxDeselectCount == 1)
  5171 			{
  5172 			s.PopCommandStack();
  5173 			OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT1, this, (TInt) err );
  5174 			SMF_RETURN(err)
  5175 			}
  5176 
  5177 		if (--iCxDeselectCount > 0)
  5178 			SMF_INVOKES(RetryGapTimerSMST,EStDeselectLoop)
  5179 
  5180 		s.PopCommandStack();
  5181 		iStackState &= ~KMMCStackStateDoDeselect;
  5182 
  5183 	SMF_STATE(EStAnalyseCommand)
  5184 
  5185 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM7, "EStAnalyseCommand" );
  5186 		TMMCCommandDesc& cmd = s.Command();
  5187 		// Check if its un-important whether the card is in transfer state (i.e
  5188 		// selected) or not for the command we are about to execute. Such
  5189 		// commands are CMD0, CMD7 and CMD13.
  5190 		
  5191 		// This state machine should never send CMD55
  5192 		if (cmd.iCommand == ECmdAppCmd)
  5193 		    {
  5194 		    OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT2, this, (TInt) KMMCErrNotSupported );
  5195 			SMF_RETURN (KMMCErrNotSupported)
  5196 		    }
  5197 
  5198 		SMF_NEXTS( EStTestAppCommand )
  5199 		if (cmd.iCommand == ECmdGoIdleState || cmd.iCommand == ECmdSelectCard || cmd.iCommand == ECmdSendStatus)
  5200 			{
  5201 			SMF_GOTONEXTS
  5202 			}
  5203 
  5204 		// See if we need to select (or deselect) this card
  5205 		TRCA targetRCA=0;
  5206 		switch( cmd.iSpec.iCommandType )
  5207 			{
  5208 			case ECmdTypeBC: case ECmdTypeBCR: case ECmdTypeAC:
  5209 			// Command which don't require the card to be selected
  5210 				break;
  5211 			case ECmdTypeACS: case ECmdTypeADTCS: case ECmdTypeADC:
  5212 			// Commands which do require the card to be selected
  5213 				{
  5214 				if ( (iConfig.iModes & KMMCModeCardControlled) == 0 )
  5215 					SMF_GOTONEXTS
  5216 				// Get the RCA of the card
  5217 				if ( (targetRCA = s.CardRCA()) == 0 )
  5218 				    {
  5219 				    OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT3, this, (TInt) KMMCErrNoCard );
  5220 					SMF_RETURN( KMMCErrNoCard )
  5221 				    }
  5222 				break;
  5223 				}
  5224 			default:
  5225 				SMF_GOTONEXTS
  5226 			}
  5227 
  5228 		// Check if this card is already in the appropriate selected/deselected
  5229 		// state for the forthcoming command.
  5230 		if (targetRCA==iSelectedCard)
  5231 			SMF_GOTONEXTS
  5232 
  5233 		// Need to select (or deselect by using RCA(0)) the card so push the
  5234 		// top-level command onto the command stack while we issue the select command.
  5235 		s.PushCommandStack();
  5236 		s.FillCommandDesc(ECmdSelectCard,targetRCA);
  5237 		SMF_INVOKES(IssueCommandCheckResponseSMST,EStSelectDone)	
  5238 
  5239 	SMF_STATE(EStSelectDone)
  5240 
  5241 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM8, "EStSelectDone" );
  5242 		TMMCCommandDesc& cmd = s.Command();
  5243 		
  5244 		if ( err )
  5245 			{
  5246 			cmd.iFlags &= ~(KMMCCmdFlagASSPFlags|KMMCCmdFlagExecSelBusy);
  5247 
  5248 			if (err == KMMCErrBusyTimeOut)
  5249 				cmd.iFlags |= KMMCCmdFlagExecSelBusy;
  5250 
  5251 			s.PopCommandStack();
  5252 			SMF_NEXTS(EStErrRecover)
  5253 			OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT4, this, (TInt) err );
  5254 			return err;		// re-enter the next state with that error
  5255 			}
  5256 
  5257 		// Are we trying to recover from a top-level command returning busy (by de-selecting and re-selecting)
  5258 		if ( cmd.iFlags & KMMCCmdFlagExecTopBusy )
  5259 			{
  5260 			cmd.iFlags &= ~KMMCCmdFlagExecTopBusy;
  5261 
  5262 			TUint32 blockLength = cmd.BlockLength();
  5263 
  5264 			if ( !(cmd.iSpec.iMultipleBlocks) || cmd.iTotalLength <= blockLength )
  5265 				SMF_EXIT		// operation is completed
  5266 
  5267 			cmd.iTotalLength    -= blockLength;
  5268 			cmd.iArgument        = TUint(cmd.iArgument) + blockLength;
  5269 			cmd.iDataMemoryP    += blockLength;
  5270 			s.iBytesTransferred += blockLength;
  5271 			cmd.iPollAttempts = 0;
  5272 			}
  5273 
  5274 		s.PopCommandStack();
  5275 		
  5276 		cmd = s.Command();
  5277 		if (!cmd.iSpec.iUseStopTransmission && cmd.iSpec.iMultipleBlocks)
  5278 			{
  5279 			// Multi-block command using SET_BLOCK_COUNT
  5280 			// This is a re-try of the data transfer, normally select (CMD7) is performed along with the issuing of CMD23, 
  5281 			// therefore need to re-issue SET_BLOCK_COUNT.....
  5282 	  		const TUint blocks = cmd.NumBlocks();
  5283 	
  5284 			s.PushCommandStack();
  5285 			s.FillCommandDesc( ECmdSetBlockCount, blocks );
  5286 			SMF_INVOKES( IssueCommandCheckResponseSMST, EStBlockCountCmdIssued )
  5287 			}
  5288 		else
  5289 			{
  5290 			SMF_GOTOS( EStTestAppCommand )
  5291 			}
  5292 
  5293 	SMF_STATE(EStBlockCountCmdIssued)
  5294 		
  5295 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM9, "EStBlockCountCmdIssued" );
  5296 		const TMMCStatus status(s.ResponseP());
  5297 		s.PopCommandStack();
  5298 		if (status.Error())
  5299 		    {
  5300 		    OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT5, this, (TInt) KMMCErrStatus );
  5301 			SMF_RETURN(KMMCErrStatus)
  5302 		    }
  5303 
  5304 		if(err & KMMCErrNotSupported)
  5305 			{
  5306 			// Not supported by the PSL, so use standard Stop Transmission mode
  5307 			s.Command().iSpec.iUseStopTransmission = ETrue;
  5308 			}
  5309 		// Fall through...		
  5310 
  5311 	SMF_STATE(EStTestAppCommand)
  5312 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM10, "EStTestAppCommand" );
  5313 		TMMCCommandDesc& cmd = s.Command();
  5314 		if (cmd.iSpec.iCommandClass != KMMCCmdClassApplication)
  5315 			SMF_GOTOS( EStIssueCommand )
  5316 
  5317 		s.PushCommandStack();
  5318 		s.FillCommandDesc(ECmdAppCmd, s.CardRCA()); // Send APP_CMD (CMD55)	
  5319 		SMF_INVOKES(IssueCommandCheckResponseSMST,EStIssueAppCommandDone)
  5320 		
  5321 	SMF_STATE(EStIssueAppCommandDone)
  5322 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM11, "EStIssueAppCommandDone" );
  5323 		s.PopCommandStack();
  5324 		if ( err )
  5325 			{
  5326 			SMF_NEXTS(EStErrRecover)
  5327             OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT6, this, (TInt) err );
  5328 			return err;		// re-enter the next state with that error
  5329 			}
  5330 
  5331 
  5332 	SMF_STATE(EStIssueCommand)
  5333 
  5334 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM12, "EStIssueCommand" );
  5335 		TMMCCommandDesc& cmd = s.Command();
  5336 		// If its an addressed command (rather than a selected command), then
  5337 		// setup the argument with the RCA. (Commands requiring card to be
  5338 		// selected - ACS don't matter since selected cards don't need an RCA now).
  5339 		if ((iConfig.iModes & KMMCModeCardControlled) && cmd.iSpec.iCommandType==ECmdTypeAC )
  5340 			{
  5341 			const TRCA targetRCA = s.CardRCA();
  5342 			if ( targetRCA == 0 )
  5343 			    {
  5344 			    OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT7, this, (TInt) KMMCErrNoCard );
  5345 				SMF_RETURN( KMMCErrNoCard )
  5346 			    }
  5347 			cmd.iArgument.SetRCA(targetRCA);
  5348 			}
  5349 
  5350 		// Issue the top-level command
  5351 		SMF_INVOKES(IssueCommandCheckResponseSMST,EStCommandIssued)
  5352 
  5353 	SMF_STATE(EStCommandIssued)
  5354 
  5355 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM13, "EStCommandIssued" );
  5356 		// If command was succesful then we've finished.
  5357 		if (!err)
  5358 			SMF_EXIT
  5359 
  5360 	SMF_STATE(EStErrRecover)
  5361 
  5362 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM14, "EStErrRecover" );
  5363 		TMMCCommandDesc& cmd = s.Command();
  5364 		const TUint32 modes=iConfig.iModes;
  5365 		SMF_NEXTS(EStRetry)
  5366 
  5367 		m.ResetTraps();							// no more re-entries via return()
  5368 
  5369 		if (cmd.iCommand == ECmdSelectCard)
  5370 			DeselectsToIssue( 1 );	// in case stby/tran synch is lost
  5371 
  5372 		if (cmd.iSpec.iMultipleBlocks && (cmd.iFlags & KMMCCmdFlagBytesValid))
  5373 			{
  5374 			cmd.iTotalLength -= cmd.iBytesDone;
  5375 			cmd.iArgument = TUint(cmd.iArgument) + cmd.iBytesDone;
  5376 			cmd.iDataMemoryP += cmd.iBytesDone;
  5377 			s.iBytesTransferred += cmd.iBytesDone;
  5378 
  5379 			if (cmd.iTotalLength < cmd.BlockLength())
  5380 				{
  5381 				DeselectsToIssue(1);
  5382 				OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT8, this, (TInt) err );
  5383 				return err;
  5384 				}
  5385 			}
  5386 
  5387 		if ((modes & KMMCModeEnableRetries) == 0)
  5388 		    {
  5389 			OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT9, this, (TInt) err );
  5390 			return err;
  5391 		    }
  5392 
  5393 		const TUint32 toMask = (KMMCErrResponseTimeOut|KMMCErrDataTimeOut);
  5394 		const TUint32 crcMask = (KMMCErrResponseCRC|KMMCErrDataCRC|KMMCErrCommandCRC);
  5395 
  5396 		if( (err & ~(toMask|crcMask)) == KMMCErrNone ) // time-outs/CRC errors
  5397 			{
  5398 			if( cmd.iSpec.iCommandType == ECmdTypeADTCS )	// for data transfer commands
  5399 				{
  5400 				DeselectsToIssue( 1 );						// enforce deselect before any retries
  5401 
  5402 				if( (modes & KMMCModeCardControlled) == 0 )
  5403 				    {
  5404 					OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT10, this, (TInt) err );
  5405 					return err;		// we wouldn't know what to select - no retries
  5406 				    }
  5407 				}
  5408 
  5409 			TUint32 gapEnabled = 0;
  5410 
  5411 			if( err & toMask )
  5412 				{
  5413 				cmd.iTimeOutRetries++;
  5414 				gapEnabled |= KMMCModeTimeOutRetryGap;
  5415 
  5416 				if( (modes & KMMCModeEnableTimeOutRetry) == 0 ||
  5417 					cmd.iTimeOutRetries > iConfig.iTimeOutRetries )
  5418 				    {
  5419 					OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT11, this, (TInt) err );
  5420 					return err;
  5421 				    }
  5422 				}
  5423 
  5424 			if( err & crcMask )
  5425 				{
  5426 				cmd.iCRCRetries++;
  5427 				gapEnabled |= KMMCModeCRCRetryGap;
  5428 
  5429 				if( (modes & KMMCModeEnableCRCRetry) == 0	||
  5430 					cmd.iCRCRetries > iConfig.iCRCRetries		||
  5431 					((err & KMMCErrDataCRC) != 0 && (modes & KMMCModeDataCRCRetry) == 0) )
  5432 				    {
  5433 					OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT12, this, (TInt) err );
  5434 					return err;
  5435 				    }
  5436 				}
  5437 
  5438 			if( (modes & gapEnabled) == gapEnabled )
  5439 				{
  5440 				if( modes & KMMCModeCardControlled )
  5441 					s.iState |= KMMCSessStateSafeInGaps;	// preemption allowed
  5442 
  5443 				SMF_CALL( RetryGapTimerSMST )
  5444 				}
  5445 
  5446 			if( (modes & (KMMCModeEnablePreemption|KMMCModePreemptOnRetry|KMMCModeCardControlled)) ==
  5447 				(KMMCModeEnablePreemption|KMMCModePreemptOnRetry|KMMCModeCardControlled) )
  5448 				{
  5449 				s.SwapMe();
  5450 				SMF_WAIT		// let the others take over the bus before retry
  5451 				}
  5452 
  5453 			// No preemption, just repeat the command
  5454 			SMF_GOTONEXTS
  5455 			}
  5456 
  5457 		if( err & KMMCErrBusInconsistent )
  5458 			{
  5459 			// ASSP layer reported that we must re-initialise the stack to recover.
  5460 			// Here we'll allow stack initialiser to take over. The control will then be transferred
  5461 			// to whoever processes KMMCErrInitContext (must be a top-level SM function)
  5462 
  5463 //			ReportInconsistentBusState();	// ASSP layer should have it done
  5464 			s.iGlobalRetries++;
  5465 
  5466 			if( s.iGlobalRetries > KMMCMaxGlobalRetries )
  5467 			    {
  5468 				OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT13, this, (TInt) err );
  5469 				return err;
  5470 			    }
  5471 
  5472 			s.SwapMe();		// To prevent the initialiser from aborting this session
  5473 			SMF_WAIT		// Initialiser will take over here
  5474 			}
  5475 
  5476 		if( err == KMMCErrBusyTimeOut )
  5477 			{
  5478 			if ((cmd.iFlags & KMMCCmdFlagExecSelBusy) == 0)	// check if that was a response
  5479 				cmd.iFlags |= KMMCCmdFlagExecTopBusy;		// to a top level command
  5480 
  5481 			DeselectsToIssue( 1 );	// force deselect as the next bus operation
  5482 			cmd.iPollAttempts++;
  5483 
  5484 			if( (modes & KMMCModeEnableBusyPoll) == 0 ||
  5485 				((modes & KMMCModeCardControlled) == 0 && cmd.iCommand != ECmdSelectCard) ||
  5486 				cmd.iPollAttempts > iConfig.iPollAttempts )
  5487 			    {
  5488 				OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT14, this, (TInt) err );
  5489 				return err;
  5490 			    }
  5491 
  5492 			if( modes & KMMCModeBusyPollGap )
  5493 				{
  5494 				s.iState |= KMMCSessStateSafeInGaps;	// preemption allowed
  5495 				SMF_CALL( PollGapTimerSMST )
  5496 				}
  5497 
  5498 			if( (modes & (KMMCModeEnablePreemption|KMMCModePreemptOnBusy)) ==
  5499 				(KMMCModeEnablePreemption|KMMCModePreemptOnBusy) )
  5500 				{
  5501 				s.SwapMe();
  5502 				SMF_WAIT		// let the others take over the bus before retry
  5503 				}
  5504 
  5505 			// No preemption, just repeat the Deselect/Select sequence
  5506 			SMF_GOTONEXTS
  5507 			}
  5508 
  5509 		OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT15, this, (TInt) err );
  5510 		return err;
  5511 
  5512 	SMF_END
  5513 	}
  5514 
  5515 TMMCErr DMMCStack::IssueCommandCheckResponseSM()
  5516 /**
  5517  * Issue a single command to the card and check the response 
  5518  *
  5519  * This generic layer child function in turn calls IssueMMCCommandSM().
  5520  *
  5521  * @return MMC error code.
  5522  */
  5523 	{
  5524 	enum states
  5525 		{
  5526 		EStBegin=0,
  5527 		EStIssueCommand,
  5528 		EStCommandIssued,
  5529 		EStEnd
  5530 		};
  5531 
  5532 		DMMCSession& s=Session();
  5533 		TMMCCommandDesc& cmd = Command();
  5534 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM1, "Current session=0x%x", &s );
  5535 
  5536 	SMF_BEGIN
  5537 
  5538 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM2, "EStBegin" );
  5539 		__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Issue %d %x",TUint(cmd.iCommand),TUint(cmd.iArgument)));
  5540 		OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM3, "CMD%02d(0x%08x)", TUint(cmd.iCommand), TUint(cmd.iArgument) );
  5541 		
  5542 		// Stop the Controller from powering down the card due to bus inactivity
  5543 		iSocket->ResetInactivity(0);
  5544 
  5545 	SMF_STATE(EStIssueCommand)
  5546 
  5547 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM4, "EStIssueCommand" );
  5548 		// If command is directed at a specific card then save this command in card object
  5549 		if (iConfig.iModes & KMMCModeCardControlled)
  5550 			{
  5551 			s.iCardP->iLastCommand = cmd.iCommand;
  5552 
  5553 			if(iMultiplexedBus)
  5554 				{
  5555 				DoSetBusWidth(BusWidthEncoding(s.CardP()->BusWidth()));
  5556 				DoSetClock(MaxTranSpeedInKilohertz(*s.CardP()));
  5557 				}
  5558 			}
  5559 
  5560 		if (cmd.iCommand==ECmdSelectCard)
  5561 			iSelectedCard = TUint16(~0);
  5562 
  5563 		// Pass the command to ASSP layer
  5564 		cmd.iFlags &= ~(KMMCCmdFlagASSPFlags|KMMCCmdFlagExecSelBusy);
  5565 		cmd.iBytesDone=0;
  5566 		m.SetTraps(KMMCErrAll);
  5567 		SMF_INVOKES(IssueMMCCommandSMST,EStCommandIssued)
  5568 
  5569 	SMF_STATE(EStCommandIssued)
  5570 
  5571 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM5, "EStCommandIssued" );
  5572 #ifdef ENABLE_DETAILED_SD_COMMAND_TRACE
  5573 		cmd.Dump(s.ResponseP(), err);
  5574 #endif
  5575 
  5576 		OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM6, "MMC Protocol: CMD%02d(0x%08x)", (TInt) cmd.iCommand, (TUint) cmd.iArgument );
  5577 		OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM7, "MMC Protocol: RSP%d - LEN 0x%08x - ERR 0x%08x - STAT 0x%08x", (TUint) cmd.iSpec.iResponseType, (TUint) cmd.iSpec.iResponseLength, (TUint) err, (TUint) TMMC::BigEndian32(s.ResponseP()) );
  5578 		
  5579 		TMMCErr exitCode=err;
  5580 		// If we have just de-selected all cards in the stack, RCA(0) then ignore response timeout.
  5581 		if ( cmd.iCommand==ECmdSelectCard && TRCA(cmd.iArgument)==0 )
  5582 			exitCode &= ~KMMCErrResponseTimeOut;
  5583 		else
  5584 			{
  5585 			// If commands returns card status and there we no command errors
  5586 			// (or the status contains errors) then save the status info.
  5587 			if ( (cmd.iFlags & KMMCCmdFlagStatusReceived) ||
  5588 				 ((exitCode==KMMCErrNone || (exitCode & KMMCErrStatus)) &&
  5589 				  (cmd.iSpec.iResponseType==ERespTypeR1 || cmd.iSpec.iResponseType==ERespTypeR1B)) )
  5590 				{
  5591 				TMMCStatus status=s.ResponseP();
  5592 				s.iLastStatus=status;
  5593 				__KTRACE_OPT(KPBUS1, Kern::Printf("mmc:ec:st=%08x", TUint32(status)));
  5594 				OstTrace1( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM8, "status=0x%08x", TUint32(status) );
  5595 
  5596 				if (iConfig.iModes & KMMCModeCardControlled)
  5597 					s.iCardP->iStatus=status;
  5598 
  5599 				// Update exit code if card status is reporting an error (in case not done already)
  5600 				if (status.Error() != 0)
  5601 					exitCode |= KMMCErrStatus;
  5602 				}
  5603 			}
  5604 
  5605 		// If we've just selected a card and the command was succesful then
  5606 		// remember which one so we don't need to do it twice.
  5607 		if (cmd.iCommand==ECmdSelectCard && exitCode==KMMCErrNone)
  5608 			iSelectedCard=TRCA(cmd.iArgument);
  5609 
  5610 		OstTraceFunctionExitExt( DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM_EXIT, this, ( TInt ) exitCode );
  5611 		SMF_RETURN(exitCode)
  5612 
  5613 	SMF_END
  5614 	}
  5615 
  5616 //
  5617 // General Client Service CIMs/Sessions; top level functions
  5618 //
  5619 inline TMMCErr DMMCStack::NakedSessionSM()
  5620 /**
  5621  * Executes an individual MMC command (as opposed to a macro).
  5622  *
  5623  * If the command is 'card controlled' it first invokes AttachCardSM() 
  5624  * before calling ExecCommandSM() to excecute the requested command.
  5625  *
  5626  * @return MMC error code.
  5627  */
  5628 	{
  5629 		enum states
  5630 			{
  5631 			EStBegin=0,
  5632 			EStAttached,
  5633 			EStFinish,
  5634 			EStEnd
  5635 			};
  5636 
  5637 		DMMCSession& s=Session();
  5638 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_NAKEDSESSIONSM1, "Current session=0x%x", &s );
  5639 
  5640 	SMF_BEGIN
  5641 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_NAKEDSESSIONSM2, "EStBegin" );
  5642 		s.iState |= KMMCSessStateInProgress;
  5643 
  5644 		if( (iConfig.iModes & KMMCModeCardControlled) != 0 )
  5645 			SMF_INVOKES( AttachCardSMST, EStAttached )
  5646 
  5647 	SMF_BPOINT(EStAttached)
  5648 
  5649 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_NAKEDSESSIONSM3, "EStAttached" );
  5650 		SMF_INVOKES( ExecCommandSMST, EStFinish )
  5651 
  5652 	SMF_STATE(EStFinish)
  5653 
  5654 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_NAKEDSESSIONSM4, "EStFinish" );
  5655 		s.iState &= ~KMMCSessStateInProgress;
  5656 	SMF_END
  5657 	}
  5658 
  5659 inline TMMCErr DMMCStack::CIMSetupCardSM()
  5660 /**
  5661  * Executes the CIM_SETUP_CARD macro.
  5662  *
  5663  * @return MMC error code.
  5664  */
  5665 	{
  5666 		enum states
  5667 			{
  5668 			EStBegin=0,
  5669 			EStAttached,
  5670 			EStSelected,
  5671 			EStGotCSD,
  5672 			EStEnd
  5673 			};
  5674 
  5675 		DMMCSession& s=Session();
  5676 		OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM1, "Current session=0x%x; Last status=0x%x", (TUint) &s, (TUint) s.iLastStatus );
  5677 
  5678 		__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:SetupCardSM %x",TUint(s.iLastStatus)));
  5679 
  5680 	SMF_BEGIN
  5681 	
  5682 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM2, "EStBegin" );
  5683 		s.iState |= KMMCSessStateInProgress;
  5684 
  5685 		SMF_INVOKES( AttachCardSMST, EStAttached )	// attachment is mandatory here
  5686 
  5687 	SMF_BPOINT(EStAttached)
  5688 
  5689 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM3, "EStAttached" );
  5690 		s.FillCommandDesc( ECmdSelectCard, 0 );
  5691 		SMF_INVOKES( ExecCommandSMST, EStSelected )
  5692 
  5693 	SMF_STATE(EStSelected)
  5694 
  5695 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM4, "EStSelected" );
  5696 		if( !s.iCardP->IsReady() )
  5697 		    {
  5698 			OstTraceFunctionExitExt( DMMCSTACK_CIMSETUPCARDSM_EXIT, this, (TInt) KMMCErrNoCard );
  5699 			return KMMCErrNoCard;
  5700 		    }
  5701 
  5702 		s.FillCommandDesc( ECmdSendCSD, Command().iArgument ); // NB: the card will be deselected to execute this command
  5703 		SMF_INVOKES( ExecCommandSMST, EStGotCSD )
  5704 
  5705 	SMF_STATE(EStGotCSD)
  5706 
  5707 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM5, "EStGotCSD" );
  5708 		s.iCardP->iCSD = s.ResponseP();
  5709 
  5710 		s.iState &= ~KMMCSessStateInProgress;
  5711 	SMF_END
  5712 	}
  5713 
  5714 EXPORT_C TMMCErr DMMCStack::CIMReadWriteBlocksSM()
  5715 /**
  5716  * This macro performs single/multiple block reads and writes.
  5717  *
  5718  * For normal read/write block operations, this function determines the appropriate
  5719  * MMC command to send and fills the command descriptor accordingly based on 
  5720  * the value of the session ID set. However, it is necessary to have set the
  5721  * command arguments (with DMMCSession::FillCommandArgs()) before this function
  5722  * is called.
  5723  *
  5724  * For special block read/write operations, e.g. lock/unlock, it is required to
  5725  * have already filled the command descriptor (with DMMCSession::FillCommandDesc())
  5726  * for the special command required - in addition to have setup the command arguments.
  5727  *
  5728  * @return MMC error code.
  5729  */
  5730 	{
  5731 		enum states
  5732 			{
  5733 			EStBegin=0,
  5734 			EStRestart,
  5735 			EStAttached,
  5736 			EStLength1,
  5737 			EStLengthSet,
  5738 			EStIssueBlockCount,
  5739 			EStAppCmdIssued,
  5740 			EStBlockCountCmdIssued,
  5741 			EStBpoint1,
  5742 			EStIssued,
  5743 			EStWaitFinish,
  5744 			EStWaitFinish1,
  5745 			EStRWFinish,
  5746 			EStEnd
  5747 			};
  5748 
  5749 		DMMCSession& s=Session();
  5750 		OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM1, "Current session=0x%x; Last status=0x%x", (TUint) &s, (TUint) s.iLastStatus );
  5751 
  5752 		__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:RWBlocksSM %x",TUint(s.iLastStatus)));
  5753 
  5754 	SMF_BEGIN
  5755 
  5756 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM2, "EStBegin" );
  5757 		if(s.iSessionID == ECIMWriteBlock || s.iSessionID == ECIMWriteMBlock)
  5758 			{
  5759 			// Check that the card supports class 4 (Write) commands
  5760 			const TUint ccc = s.iCardP->CSD().CCC();
  5761 			if(!(ccc & KMMCCmdClassBlockWrite))
  5762 			    {
  5763 				OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT1, this, (TInt) KMMCErrNotSupported );
  5764 				return KMMCErrNotSupported;
  5765 			    }
  5766 			}
  5767 
  5768 		s.iState |= KMMCSessStateInProgress;
  5769 		m.SetTraps(KMMCErrInitContext);
  5770 
  5771 	SMF_STATE(EStRestart)		// NB: ErrBypass is not processed here
  5772 
  5773 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM3, "EStRestart" );
  5774 		SMF_CALLMEWR(EStRestart) // Create a recursive call entry to recover from the errors trapped
  5775 		m.SetTraps(KMMCErrStatus);
  5776 		if (s.Command().iSpec.iCommandClass!=KMMCCmdClassApplication || s.Command().iCommand==ECmdAppCmd)
  5777 			{
  5778 			s.ResetCommandStack();
  5779 			SMF_INVOKES( AttachCardSMST, EStAttached )	// attachment is mandatory here
  5780 			}
  5781 
  5782 	SMF_BPOINT(EStAttached)
  5783 
  5784 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM4, "EStAttached" );
  5785 		TMMCCommandDesc& cmd = s.Command();
  5786 
  5787 		const TUint32 blockLength = cmd.BlockLength();
  5788 		if(blockLength == 0)
  5789 		    {
  5790 			OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT2, this, (TInt) KMMCErrArgument );
  5791 			return KMMCErrArgument;
  5792 		    }
  5793 
  5794 		if(s.iSessionID == ECIMReadBlock	||
  5795 		   s.iSessionID == ECIMWriteBlock	||
  5796 		   s.iSessionID == ECIMReadMBlock	||
  5797 		   s.iSessionID == ECIMWriteMBlock)
  5798 			{	
  5799 			// read/write operation
  5800 			if(!cmd.AdjustForBlockOrByteAccess(s))
  5801 				{
  5802 				// unable to convert command arguments to suit the underlying block/byte access mode
  5803 				OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT3, this, (TInt) KMMCErrArgument );
  5804 				return KMMCErrArgument;
  5805 				}
  5806 			}
  5807 
  5808 		// Set the block length if it has changed. Always set for ECIMLockUnlock.
  5809 		if ((blockLength == s.iCardP->iSetBlockLen) && (s.iSessionID != ECIMLockUnlock))
  5810 			{
  5811 			SMF_GOTOS( EStLengthSet )
  5812 			}
  5813 
  5814 		s.iCardP->iSetBlockLen = 0;
  5815 		s.PushCommandStack();
  5816 		s.FillCommandDesc( ECmdSetBlockLen, blockLength );
  5817 		SMF_INVOKES( ExecCommandSMST, EStLength1 )
  5818 
  5819 	SMF_STATE(EStLength1)
  5820 
  5821 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM5, "EStAttached" );
  5822 		const TMMCStatus status(s.ResponseP());
  5823 		s.PopCommandStack();
  5824 		if (status.Error())
  5825 		    {
  5826 		    OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT4, this, (TInt) KMMCErrStatus );
  5827 			SMF_RETURN(KMMCErrStatus)
  5828 		    }
  5829 		s.iCardP->iSetBlockLen = s.Command().BlockLength();
  5830 
  5831 	SMF_STATE(EStLengthSet)
  5832 
  5833 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM6, "EStLengthSet" );
  5834 		TMMCCommandDesc& cmd = s.Command();
  5835 		TUint opType = 0;
  5836 		const TUint kTypeWrite =	KBit0;
  5837 		const TUint kTypeMultiple =	KBit1;
  5838 		const TUint kTypeSpecial =	KBit2;
  5839 		static const TMMCCommandEnum cmdCodes[4] =
  5840 			{ECmdReadSingleBlock, ECmdWriteBlock, ECmdReadMultipleBlock, ECmdWriteMultipleBlock};
  5841 
  5842 		switch( s.iSessionID )
  5843 			{
  5844 			case ECIMReadBlock:
  5845 				break;
  5846 			case ECIMWriteBlock:
  5847 				opType=kTypeWrite;
  5848 				break;
  5849 			case ECIMReadMBlock:
  5850 				opType=kTypeMultiple;
  5851 				break;
  5852 			case ECIMWriteMBlock:
  5853 				opType=kTypeWrite|kTypeMultiple;
  5854 				break;
  5855 			case ECIMLockUnlock:
  5856 			default:
  5857 				opType=kTypeSpecial;
  5858 				break;
  5859 			}
  5860 
  5861   		const TUint blocks = cmd.NumBlocks();
  5862 
  5863 		SMF_NEXTS(EStBpoint1)
  5864 		if ( !(opType & kTypeSpecial) )	// A special session has already set its command descriptor
  5865 			{
  5866 			
  5867 			if (cmd.iFlags & KMMCCmdFlagReliableWrite)
  5868 				//ensure multiple block commands are used for reliable writing
  5869 				opType |= kTypeMultiple;
  5870 			
  5871 			if ( (blocks==1) && !(cmd.iFlags & KMMCCmdFlagReliableWrite) )
  5872 				{
  5873 				// Reliable Write requires that Multi-Block command is used.
  5874 				opType &= ~kTypeMultiple;
  5875 				}
  5876 
  5877 			TUint32 oldFlags = cmd.iFlags;	// Maintain old flags which would be overwritten by FillCommandDesc
  5878 			cmd.iCommand = cmdCodes[opType];
  5879 			s.FillCommandDesc();
  5880 			cmd.iFlags = oldFlags;			// ...and restore
  5881 
  5882 			if((opType & kTypeMultiple) == kTypeMultiple)
  5883 				{
  5884 				//
  5885 				// This is a Multiple-Block DT command.  Check the version of the card, as
  5886 				// MMC Version 3.1 onwards supports the SET_BLOCK_COUNT mode for DT.
  5887 				//
  5888 				// Note that if the PSL does not support pre-determined block count of
  5889 				// data transmission, then it may return KMMCErrNotSupported to force
  5890 				// the 'Stop Transmission' mode to be used instead.
  5891 				//
  5892 				if(s.iCardP->CSD().SpecVers() >= 3)
  5893 					{
  5894 					OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM7, "CMD12 (STOP_TRANSMISSION) not used" );
  5895 					
  5896 					cmd.iSpec.iUseStopTransmission = EFalse;
  5897 					SMF_NEXTS(EStIssueBlockCount)
  5898 					}
  5899 				else
  5900 					{
  5901 					cmd.iSpec.iUseStopTransmission = ETrue;
  5902 					}
  5903 				}
  5904 			}
  5905 
  5906 		SMF_GOTONEXTS
  5907 
  5908 	SMF_STATE(EStIssueBlockCount)
  5909 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM8, "EStIssueBlockCount" );
  5910 		//
  5911 		// Issues SET_BLOCK_COUNT (CMD23) for MB R/W data transfers.
  5912 		// This is only issued if MMC version >= 3.1 and the PSL
  5913 		// supports this mode of operation.
  5914 		//
  5915 		TMMCCommandDesc& cmd = s.Command();
  5916   		TUint32 args = (TUint16)cmd.NumBlocks();
  5917 	
  5918 		m.SetTraps(KMMCErrStatus | KMMCErrNotSupported);
  5919 
  5920 		if (cmd.iFlags & KMMCCmdFlagReliableWrite)
  5921 			{
  5922 			// Command marked as Reliable Write 
  5923 			// set Bit31 in CMD23 argument
  5924 			args |= KMMCCmdReliableWrite;
  5925 			}
  5926 		
  5927 		s.PushCommandStack();
  5928 		s.FillCommandDesc( ECmdSetBlockCount, args );
  5929 		SMF_INVOKES( ExecCommandSMST, EStBlockCountCmdIssued )
  5930 
  5931 	SMF_STATE(EStBlockCountCmdIssued)
  5932 		
  5933 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM9, "EStBlockCountCmdIssued" );
  5934 		const TMMCStatus status(s.ResponseP());
  5935 		s.PopCommandStack();
  5936 		if (status.Error())
  5937 		    {
  5938 		    OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT5, this, (TInt) KMMCErrStatus );
  5939 			SMF_RETURN(KMMCErrStatus)
  5940 		    }
  5941 
  5942 		if(err & KMMCErrNotSupported)
  5943 			{
  5944 			// Not supported by the PSL, so use standard Stop Transmission mode
  5945 			s.Command().iSpec.iUseStopTransmission = ETrue;
  5946 			}
  5947 
  5948 		SMF_GOTOS(EStBpoint1)
  5949 
  5950 	SMF_STATE(EStAppCmdIssued)
  5951 
  5952 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM10, "EStAppCmdIssued" );
  5953 		const TMMCStatus status(s.ResponseP());
  5954 		s.PopCommandStack();
  5955 		if (status.Error())
  5956 		    {
  5957 		    OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT6, this, (TInt) KMMCErrStatus );
  5958 			SMF_RETURN(KMMCErrStatus)
  5959 		    }
  5960 
  5961 	SMF_BPOINT(EStBpoint1)
  5962 
  5963 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM11, "EStBpoint1" );
  5964 		// NB We need to trap KMMCErrStatus errors, because if one occurs, 
  5965 		// we still need to wait to exit PRG/RCV/DATA state 
  5966 		m.SetTraps(KMMCErrStatus);
  5967 
  5968 		SMF_INVOKES( ExecCommandSMST, EStIssued )
  5969 
  5970 	SMF_STATE(EStIssued)
  5971 
  5972 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM12, "EStIssued" );
  5973 		// check state of card after data transfer with CMD13.
  5974 
  5975 		if (s.Command().Direction() != 0)
  5976 			{
  5977 			SMF_GOTOS(EStWaitFinish)
  5978 			}
  5979 
  5980 		SMF_GOTOS(EStRWFinish);
  5981 
  5982 	SMF_STATE(EStWaitFinish)
  5983 
  5984 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM13, "EStWaitFinish" );
  5985 		// Save the status and examine it after issuing CMD13...
  5986 		// NB We don't know where in the command stack the last response is stored (e.g. there may 
  5987 		// have bee a Deselect/Select issued), but we do know last response is stored in iLastStatus
  5988 		TMMC::BigEndian4Bytes(s.ResponseP(), s.iLastStatus);
  5989 
  5990 		s.PushCommandStack();
  5991 		s.FillCommandDesc(ECmdSendStatus, 0);
  5992 		SMF_INVOKES(ExecCommandSMST, EStWaitFinish1)
  5993 
  5994 	SMF_STATE(EStWaitFinish1)
  5995 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM14, "EStWaitFinish1" );
  5996 		const TMMCStatus status(s.ResponseP());
  5997 		s.PopCommandStack();
  5998 
  5999 #ifdef __WINS__
  6000 		SMF_GOTOS(EStRWFinish);
  6001 #else
  6002 		const TMMCardStateEnum st1 = status.State();
  6003 		if (st1 == ECardStatePrg || st1 == ECardStateRcv || st1 == ECardStateData)
  6004 			{
  6005 			SMF_INVOKES(ProgramTimerSMST, EStWaitFinish);
  6006 			}
  6007 		if (status.Error())
  6008 		    {
  6009 		    OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT7, this, (TInt) KMMCErrStatus );
  6010 			SMF_RETURN(KMMCErrStatus)
  6011 		    }
  6012 #endif
  6013 		
  6014 		// Fall through if CURRENT_STATE is not PGM or DATA
  6015 	SMF_STATE(EStRWFinish)
  6016 
  6017 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM15, "EStRWFinish" );
  6018 		if (TMMCStatus(s.ResponseP()).Error() != 0)
  6019 		    {
  6020 		    OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT8, this, (TInt) KMMCErrStatus );
  6021 			SMF_RETURN(KMMCErrStatus);
  6022 		    }
  6023 
  6024 		s.iState &= ~KMMCSessStateInProgress;
  6025 
  6026 		// skip over recursive entry or throw error and catch in CIMLockUnlockSM()
  6027 		TMMCErr ret = (s.Command().iCommand == ECmdLockUnlock) ? KMMCErrUpdPswd : KMMCErrBypass; 
  6028 		OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT9, this, (TInt) ret );
  6029 		return ret;
  6030 
  6031 	SMF_END
  6032 	}
  6033 
  6034 inline TMMCErr DMMCStack::CIMEraseSM()
  6035 /**
  6036  * This macro performs sector/group erase of a continuous area
  6037  *
  6038  * @return MMC error code.
  6039  */
  6040 	{
  6041 		enum states
  6042 			{
  6043 			EStBegin=0,
  6044 			EStRestart,
  6045 			EStAttached,
  6046 			EStStartTagged,
  6047 			EStEndTagged,
  6048 			EStErased,
  6049 			EStWaitFinish,
  6050 			EStWaitFinish1,
  6051 			EStEraseFinish,
  6052 			EStEnd
  6053 			};
  6054 
  6055 		DMMCSession& s=Session();
  6056 		OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_CIMERASESM1, "Current session=0x%x; Last status=0x%x", (TUint) &s, (TUint) s.iLastStatus );
  6057 		
  6058 
  6059 		__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:EraseSM %x",TUint(s.iLastStatus)));
  6060 
  6061 	SMF_BEGIN
  6062 
  6063 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM2, "EStBegin" );
  6064 		// Check that the card supports class 4 (Write) commands
  6065 		const TUint ccc = s.iCardP->CSD().CCC();
  6066 		if(!(ccc & KMMCCmdClassErase))
  6067 		    {
  6068 			OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT1, this, (TInt) KMMCErrNotSupported );
  6069 			return KMMCErrNotSupported;
  6070 		    }
  6071 
  6072 		s.iState |= KMMCSessStateInProgress;
  6073 		m.SetTraps( KMMCErrInitContext );
  6074 
  6075 	SMF_STATE(EStRestart)
  6076 
  6077 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM3, "EStRestart" );
  6078 		SMF_CALLMEWR(EStRestart) // Create a recursive call entry to recover from Init
  6079 
  6080 		s.ResetCommandStack();
  6081 		SMF_INVOKES( AttachCardSMST, EStAttached )		// attachment is mandatory
  6082 
  6083 	SMF_BPOINT(EStAttached)
  6084 
  6085 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM4, "EStAttached" );
  6086 		TMMCCommandDesc& cmd = s.Command();
  6087 
  6088 		if(cmd.iTotalLength == 0)
  6089 		    {
  6090 			OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT2, this, (TInt) KMMCErrArgument );
  6091 			return KMMCErrArgument;
  6092 		    }
  6093 
  6094 		switch( s.iSessionID )
  6095 			{
  6096 			case ECIMEraseSector:
  6097 				OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM5, "ECIMEraseSector" );
  6098 				TMMCEraseInfo eraseInfo;
  6099 				s.iCardP->GetEraseInfo(eraseInfo);
  6100 				cmd.iBlockLength = eraseInfo.iMinEraseSectorSize;
  6101 				cmd.iCommand = ECmdTagSectorStart;
  6102 				break;
  6103 			case ECIMEraseGroup:
  6104 				OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM6, "ECIMEraseGroup" );
  6105 				cmd.iBlockLength = s.iCardP->iCSD.EraseGroupSize();
  6106 				if(cmd.iBlockLength == 0 || cmd.iTotalLength % cmd.iBlockLength != 0)
  6107 				    {
  6108 					OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT3, this, (TInt) KMMCErrArgument );
  6109 					return KMMCErrArgument;
  6110 				    }
  6111 				cmd.iCommand = ECmdTagEraseGroupStart;
  6112 				break;
  6113 			default:
  6114 				DMMCSocket::Panic(DMMCSocket::EMMCEraseSessionID);
  6115 			}
  6116 
  6117 		if(!cmd.AdjustForBlockOrByteAccess(s))
  6118 		    {
  6119 			OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT4, this, (TInt) KMMCErrArgument );
  6120 			return KMMCErrArgument;
  6121 		    }
  6122 
  6123 		iConfig.RemoveMode( KMMCModeEnablePreemption );	// erase sequence must not be pre-empted
  6124 
  6125 		const TUint flags = cmd.iFlags;
  6126 		s.FillCommandDesc();
  6127 		cmd.iFlags = flags;
  6128 		SMF_INVOKES( ExecCommandSMST, EStStartTagged )
  6129 
  6130 	SMF_STATE(EStStartTagged)
  6131 
  6132 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM7, "EStStartTagged" );
  6133 		const TMMCCommandDesc& cmd = s.Command();
  6134 
  6135 		TMMCCommandEnum command;
  6136 		TUint endAddr = cmd.iArgument;
  6137 		if(s.iSessionID == ECIMEraseSector)
  6138 			{
  6139 			endAddr += cmd.IsBlockCmd() ? (cmd.iTotalLength / cmd.iBlockLength - 1) : (cmd.iTotalLength - cmd.iBlockLength);
  6140 			command = ECmdTagSectorEnd;
  6141 			}
  6142 		else
  6143 			{
  6144 			if(cmd.IsBlockCmd())
  6145 				{
  6146 				endAddr += (cmd.iTotalLength - cmd.iBlockLength) >> KMMCardHighCapBlockSizeLog2;
  6147 				}
  6148 			else
  6149 				{
  6150 				endAddr += cmd.iTotalLength - cmd.iBlockLength;
  6151 				}
  6152 	
  6153 			command = ECmdTagEraseGroupEnd;
  6154 			}
  6155 
  6156 		s.PushCommandStack();
  6157 		s.FillCommandDesc( command, endAddr );
  6158 		SMF_INVOKES( ExecCommandSMST, EStEndTagged )
  6159 
  6160 	SMF_STATE(EStEndTagged)
  6161 
  6162 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM8, "EStEndTagged" );
  6163 		// Increase the inactivity timeout as an erase operation can potentially take a long time
  6164 		// At the moment this is a somewhat arbitrary 30 seconds. This could be calculated more accurately
  6165 		// using TAAC,NSAC, R2W_FACTOR etc. but that seems to yield very large values (?)
  6166 		const TInt KMaxEraseTimeoutInSeconds = 30;
  6167 		iBody->SetInactivityTimeout(KMaxEraseTimeoutInSeconds);
  6168 		m.SetTraps(KMMCErrAll);
  6169 		s.FillCommandDesc( ECmdErase, 0 );
  6170 		SMF_INVOKES( ExecCommandSMST, EStErased )
  6171 
  6172 	SMF_STATE(EStErased)
  6173 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM9, "EStErased" );
  6174 		m.SetTraps( KMMCErrInitContext );
  6175 		iBody->RestoreInactivityTimeout();
  6176 		if (err != KMMCErrNone)
  6177 		    {
  6178 		    OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT5, this, (TInt) err );
  6179 			SMF_RETURN(err);
  6180 		    }
  6181 
  6182 
  6183 	SMF_STATE(EStWaitFinish)
  6184 
  6185 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM10, "EStWaitFinish" );
  6186 		s.PushCommandStack();
  6187 		s.FillCommandDesc(ECmdSendStatus, 0);
  6188 		SMF_INVOKES(ExecCommandSMST, EStWaitFinish1)
  6189 
  6190 	SMF_STATE(EStWaitFinish1)
  6191 
  6192 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM11, "EStWaitFinish1" );
  6193 		const TMMCStatus st(s.ResponseP());
  6194 		s.PopCommandStack();
  6195 
  6196 #ifdef __WINS__
  6197 		SMF_GOTOS(EStEraseFinish);
  6198 #else
  6199 		const TMMCardStateEnum st1 = st.State();
  6200 		if (st1 == ECardStatePrg || st1 == ECardStateRcv || st1 == ECardStateData)
  6201 			{
  6202 			SMF_INVOKES(ProgramTimerSMST, EStWaitFinish);
  6203 			}
  6204 #endif
  6205 		
  6206 		// Fall through if CURRENT_STATE is not PGM or DATA
  6207 	SMF_STATE(EStEraseFinish)
  6208 
  6209 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM12, "EStEraseFinish" );
  6210 		s.iState &= ~KMMCSessStateInProgress;
  6211 		OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT6, this, (TInt) KMMCErrBypass );
  6212 		return KMMCErrBypass;		// to skip over the recursive entry
  6213 
  6214 	SMF_END
  6215 	}
  6216 
  6217 inline TMMCErr DMMCStack::CIMReadWriteIOSM()
  6218 /**
  6219  * This macro reads/writes a stream of bytes from/to an I/O register. 
  6220  * This is a generalised form of FAST_IO (CMD39) MMC command.
  6221  *
  6222  * @return MMC error code.
  6223  */
  6224 	{
  6225 		enum states
  6226 			{
  6227 			EStBegin=0,
  6228 			EStReadIO,
  6229 			EStIOLoop,
  6230 			EStEnd
  6231 			};
  6232 
  6233 		DMMCSession& s=Session();
  6234 		TMMCCommandDesc& cmd = s.Command();
  6235 		OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEIOSM1, "Current session=0x%x; Last status=0x%x", (TUint) &s, (TUint) s.iLastStatus );
  6236 		
  6237 
  6238 		__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:IOSM %x",TUint(s.iLastStatus)));
  6239 
  6240 	SMF_BEGIN
  6241 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEIOSM2, "EStBegin" );
  6242 		s.iState |= KMMCSessStateInProgress;
  6243 		TUint argument = (TUint(cmd.iArgument)&0x7F) << 8; // shift reg addr into a proper position
  6244 
  6245 		switch( s.iSessionID )
  6246 			{
  6247 			case ECIMReadIO:
  6248 				break;
  6249 			case ECIMWriteIO:
  6250 				argument |= 0x8000;
  6251 				break;
  6252 			default:
  6253 				DMMCSocket::Panic(DMMCSocket::EMMCIOSessionID);
  6254 			}
  6255 
  6256 		s.FillCommandDesc( ECmdFastIO, argument );
  6257 		s.iBytesTransferred = ~0UL;
  6258 
  6259 		SMF_INVOKES( AttachCardSMST, EStIOLoop )	// attachment's mandatory
  6260 
  6261 	SMF_STATE(EStReadIO)
  6262 
  6263 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEIOSM3, "EStReadIO" );
  6264 		*(cmd.iDataMemoryP)++ = s.ResponseP()[3];
  6265 		cmd.iTotalLength--;
  6266 
  6267 	SMF_BPOINT(EStIOLoop)
  6268 
  6269 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEIOSM4, "EStIOLoop" );
  6270 		s.iBytesTransferred++;
  6271 
  6272 		if( cmd.iTotalLength == 0 )
  6273 			{
  6274 			s.iState &= ~KMMCSessStateInProgress;
  6275 			SMF_EXIT
  6276 			}
  6277 
  6278 		if( s.iSessionID == ECIMWriteIO )
  6279 			{
  6280 			TUint8 byte = *(cmd.iDataMemoryP)++;
  6281 			cmd.iTotalLength--;
  6282 			cmd.iArgument = (TUint(cmd.iArgument)&0xFF00) | byte;
  6283 			}
  6284 		else
  6285 			SMF_NEXTS(EStReadIO)
  6286 
  6287 		iConfig.RemoveMode( KMMCModeEnableRetries );	// no retries on I/O registers!
  6288 
  6289 		SMF_CALL( ExecCommandSMST )
  6290 
  6291 	SMF_END
  6292 	}
  6293 
  6294 inline TMMCErr DMMCStack::CIMLockUnlockSM()
  6295 /**
  6296  * Locking and unlocking a card involves writing a data block to the card.
  6297  * CIMReadWriteBlocksSM() could be used directly, but, in practive, a card must
  6298  * sometimes be sent the data block twice.
  6299  *
  6300  * @return MMC error code.
  6301  */
  6302 	{
  6303 		enum states
  6304 			{
  6305 			EStBegin,
  6306 			EStRetry,
  6307 			EStTestR1,
  6308 			EStEnd
  6309 			};
  6310 
  6311 		DMMCSession& s=Session();
  6312 		TMMCCommandDesc& cmd = Command();
  6313 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM1, "Current session=0x%x", &s );
  6314 
  6315 		__KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm"));
  6316 
  6317 	SMF_BEGIN
  6318         
  6319 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM2, "EStBegin" );
  6320 		m.SetTraps(KMMCErrStatus | KMMCErrUpdPswd);
  6321 		cmd.iUnlockRetries = 0;					// attempt counter
  6322 		iCMD42CmdByte = cmd.iDataMemoryP[0];
  6323 
  6324 	SMF_STATE(EStRetry)
  6325 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM3, "EStRetry" );
  6326 		__KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm:%x/%x", cmd.iUnlockRetries, (iSessionP == &iAutoUnlockSession) ? KMMCMaxAutoUnlockRetries : iConfig.iUnlockRetries));
  6327 
  6328 	if (iCMD42CmdByte == KMMCLockUnlockErase)
  6329 		{
  6330 		// Section 4.6.2 of version 4.2 of the the MMC specification states that 
  6331 		// the maximum time for a force erase operation should be 3 minutes 
  6332 		const TInt KMaxForceEraseTimeoutInSeconds = 3 * 60;
  6333 		iBody->SetInactivityTimeout(KMaxForceEraseTimeoutInSeconds);
  6334 		m.SetTraps(KMMCErrAll);
  6335 		}
  6336 
  6337 
  6338 		SMF_INVOKES(CIMReadWriteBlocksSMST, EStTestR1);
  6339 	
  6340 	SMF_STATE(EStTestR1)
  6341 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM4, "EStTestR1" );
  6342 		if (iCMD42CmdByte == KMMCLockUnlockErase)
  6343 			{
  6344 			m.SetTraps(KMMCErrStatus | KMMCErrUpdPswd);
  6345 			iBody->RestoreInactivityTimeout();
  6346 			}
  6347 
  6348 		if (err & KMMCErrStatus)
  6349 			{
  6350 			const TMMCStatus st = s.LastStatus();	// set in ExecCommandSM() / EStCommandIssued
  6351 			TMMCCommandDesc& cmd0 = Command();
  6352 			
  6353 			__KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm:EStTestR1 [err: %08x, st:%08x] : RETRY [%d]", 
  6354 											  err, (TInt)s.LastStatus(), cmd0.iUnlockRetries));
  6355 			OstTraceExt3( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM5, "err=%08x; Last status=%d; Unlock retries=%d", (TUint) err, (TInt) s.LastStatus(), (TUint) cmd0.iUnlockRetries );
  6356 
  6357 			const TInt KMaxRetries = (iSessionP == &iAutoUnlockSession) ? KMMCMaxAutoUnlockRetries : iConfig.iUnlockRetries;
  6358 			
  6359 			// retry if LOCK_UNLOCK_FAIL only error bit
  6360 			if (!(	iCMD42CmdByte == 0	// LOCK_UNLOCK = 0; SET_PWD = 0
  6361 				&&	err == KMMCErrStatus && st.Error() == KMMCStatErrLockUnlock
  6362 				&&	(iConfig.iModes & KMMCModeEnableUnlockRetry) != 0
  6363 				&&	++cmd0.iUnlockRetries < KMaxRetries ))
  6364 				{
  6365 				__KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm:abt"));
  6366                 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM6, "LockUnlock abort" );
  6367                 OstTraceFunctionExitExt( DMMCSTACK_CIMLOCKUNLOCKSM_EXIT, this, (TInt) err );
  6368 				SMF_RETURN(err);
  6369 				}
  6370 
  6371 			__KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm:retry"));
  6372 			OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM7, "LockUnlock retry" );
  6373 
  6374 #ifdef __EPOC32__
  6375 			s.SynchBlock(KMMCBlockOnRetryTimer);
  6376 			s.iRetryTimer.OneShot(KMMCUnlockRetryGapInMilliseconds,EFalse);
  6377 			SMF_WAITS(EStRetry)
  6378 #else
  6379 			SMF_GOTOS(EStRetry);
  6380 #endif
  6381 			}
  6382 		else if (err & KMMCErrUpdPswd)
  6383 			{
  6384 			// CMD42 executed successfully, so update 'Has Password' flag
  6385 			if ((iCMD42CmdByte & (KMMCLockUnlockClrPwd | KMMCLockUnlockErase)) != 0)
  6386 				{
  6387 				s.CardP()->iFlags&=(~KMMCardHasPassword);
  6388 				}
  6389 			else if ((iCMD42CmdByte & KMMCLockUnlockSetPwd) != 0)
  6390 				{
  6391 				s.CardP()->iFlags|=KMMCardHasPassword;
  6392 				}
  6393 			
  6394 			SMF_EXIT;
  6395 			}
  6396 		else if (err != KMMCErrNone)
  6397 			{
  6398 			OstTraceFunctionExitExt( DMMCSTACK_CIMLOCKUNLOCKSM_EXIT2, this, (TInt) err );
  6399 			SMF_RETURN(err);
  6400 			}
  6401 
  6402 
  6403 	SMF_END
  6404 	}
  6405 
  6406 inline TMMCErr DMMCStack::CIMAutoUnlockSM()
  6407 /**
  6408  * Performs auto-unlocking of the card stack
  6409  *
  6410  * @return MMC error code
  6411  */
  6412 	{
  6413 		enum states
  6414 			{
  6415 			EStBegin=0,
  6416 			EStNextIndex,
  6417 			EStInitStackAfterUnlock,
  6418 			EStIssuedLockUnlock,
  6419 			EStDone,
  6420 			EStEnd
  6421 			};
  6422 
  6423 		__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:CIMAutoUnlockSM"));
  6424 
  6425 		DMMCSession& s=Session();
  6426 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM1, "Current session=0x%x", &s );
  6427 
  6428 	SMF_BEGIN
  6429 
  6430 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM2, "EStBegin" );
  6431 		iAutoUnlockIndex = -1;
  6432 
  6433 		m.SetTraps(KMMCErrAll);	// Trap (and ignore) all errors during auto-unlock
  6434 
  6435 	SMF_STATE(EStNextIndex)
  6436 
  6437 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM3, "EStNextIndex" );
  6438 		if(err)
  6439 			{
  6440 			iSocket->PasswordControlEnd(&Session(), err);
  6441 			}
  6442 
  6443 		// the cycle is finished when iAutoUnlockIndex == KMaxMultiMediaCardsPerStack
  6444 		
  6445 		if(iAutoUnlockIndex >= TInt(KMaxMMCardsPerStack))
  6446 			{
  6447 			SMF_GOTOS(EStInitStackAfterUnlock);
  6448 			}
  6449 
  6450 		// find next available card with password in the controller store
  6451 
  6452 		const TMapping *mp = NULL;
  6453 
  6454 		TBool useIndex = EFalse;
  6455 		for (++iAutoUnlockIndex; iAutoUnlockIndex < TInt(KMaxMMCardsPerStack); ++iAutoUnlockIndex)
  6456 			{
  6457 			useIndex =							// card must be present with valid mapping
  6458 					iCardArray->CardP(iAutoUnlockIndex)->IsPresent()
  6459 				&&	(mp = iSocket->iPasswordStore->FindMappingInStore(iCardArray->CardP(iAutoUnlockIndex)->CID())) != NULL
  6460 				&&	mp->iState == TMapping::EStValid;
  6461 
  6462 			// don't increment iAutoUnlockIndex in continuation loop
  6463 			if (useIndex)
  6464 				break;
  6465 			}
  6466 
  6467 		if (! useIndex)
  6468 			{
  6469 			// if no usable index, complete with no error code
  6470 			SMF_GOTOS(EStInitStackAfterUnlock);
  6471 			}
  6472 
  6473 		//
  6474 		// We've found a locked card with a password in the password store,
  6475 		// so attempt to unlock using the CIMLockUnlockSMST state machine.
  6476 		//
  6477 		// Upon completion, test the next card before performing further initialisation.
  6478 		//
  6479 
  6480 		TMMCard &cd = *(iCardArray->CardP(iAutoUnlockIndex++));
  6481 		OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM4, "Attempting to unlock card %d", cd.Number() );
  6482 		
  6483 		s.SetCard(&cd);
  6484 
  6485 		const TInt kPWD_LEN = mp->iPWD.Length();
  6486 		iPSLBuf[0] = 0;				// LOCK_UNLOCK = 0; unlock
  6487 		iPSLBuf[1] = static_cast<TUint8>(kPWD_LEN);
  6488 		TPtr8 pwd(&iPSLBuf[2], kPWD_LEN);
  6489 		pwd.Copy(mp->iPWD);
  6490 
  6491 		const TInt kBlockLen = 1 + 1 + kPWD_LEN;
  6492 
  6493 		s.FillCommandDesc(ECmdLockUnlock);
  6494 		s.FillCommandArgs(0, kBlockLen, iPSLBuf, kBlockLen);
  6495 
  6496 		SMF_INVOKES( CIMLockUnlockSMST, EStNextIndex )
  6497 
  6498 	SMF_STATE(EStInitStackAfterUnlock)
  6499 
  6500 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM5, "EStInitStackAfterUnlock" );
  6501 		//
  6502 		// We've attempted to unlock all cards (successfully or not)
  6503 		//  - Now perform second-stage initialisation that can only be performed
  6504 		//    on unlocked cards (such as setting bus width, high speed etc..)
  6505 		//
  6506 
  6507 		m.ResetTraps();
  6508 
  6509 		SMF_INVOKES( InitStackAfterUnlockSMST, EStDone )
  6510 
  6511 	SMF_STATE(EStDone)
  6512 		OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM6, "EStDone" );
  6513 
  6514 	SMF_END
  6515 	}
  6516 
  6517 inline TMMCErr DMMCStack::NoSessionSM()
  6518 /**
  6519  * A null state machine function. Just returns KMMCErrNotSupported.
  6520  *
  6521  * @return KMMCErrNotSupported
  6522  */
  6523 	{
  6524 		enum states
  6525 			{
  6526 			EStBegin=0,
  6527 			EStEnd
  6528 			};
  6529 
  6530 	SMF_BEGIN
  6531 
  6532 		return( KMMCErrNotSupported );
  6533 
  6534 	SMF_END
  6535 	}
  6536 
  6537 //
  6538 // Static adapter functions to top-level state machines.
  6539 //
  6540 
  6541 TMMCErr DMMCStack::NakedSessionSMST(TAny* aStackP)			// ECIMNakedSession
  6542 	{ return( static_cast<DMMCStack *>(aStackP)->NakedSessionSM() ); }
  6543 
  6544 TMMCErr DMMCStack::CIMUpdateAcqSMST( TAny* aStackP )		// ECIMUpdateAcq
  6545 	{ return( static_cast<DMMCStack *>(aStackP)->CIMUpdateAcqSM() ); }
  6546 
  6547 TMMCErr DMMCStack::CIMInitStackSMST( TAny* aStackP )		// ECIMInitStack
  6548 	{ return( static_cast<DMMCStack *>(aStackP)->CIMInitStackSM() ); }
  6549 
  6550 TMMCErr DMMCStack::CIMCheckStackSMST( TAny* aStackP )		// ECIMCheckStack
  6551 	{ return( static_cast<DMMCStack *>(aStackP)->CIMCheckStackSM() ); }
  6552 
  6553 TMMCErr DMMCStack::CIMSetupCardSMST(TAny* aStackP)			// ECIMSetupCard
  6554 	{ return( static_cast<DMMCStack *>(aStackP)->CIMSetupCardSM() ); }
  6555 
  6556 EXPORT_C TMMCErr DMMCStack::CIMReadWriteBlocksSMST(TAny* aStackP)	// ECIMReadBlock, ECIMWriteBlock, ECIMReadMBlock, ECIMWriteMBlock
  6557 	{ return( static_cast<DMMCStack *>(aStackP)->CIMReadWriteBlocksSM() ); }
  6558 
  6559 TMMCErr DMMCStack::CIMEraseSMST(TAny* aStackP)				// ECIMEraseSector, ECIMEraseGroup
  6560 	{ return( static_cast<DMMCStack *>(aStackP)->CIMEraseSM() ); }
  6561 
  6562 TMMCErr DMMCStack::CIMReadWriteIOSMST(TAny* aStackP)		// ECIMReadIO, ECIMWriteIO
  6563 	{ return( static_cast<DMMCStack *>(aStackP)->CIMReadWriteIOSM() ); }
  6564 
  6565 TMMCErr DMMCStack::CIMLockUnlockSMST(TAny* aStackP)			// ECIMLockUnlock
  6566 	{ return( static_cast<DMMCStack *>(aStackP)->CIMLockUnlockSM() ); }
  6567 
  6568 TMMCErr DMMCStack::NoSessionSMST(TAny* aStackP)				// ECIMLockStack
  6569 	{ return( static_cast<DMMCStack *>(aStackP)->NoSessionSM() ); }
  6570 
  6571 TMMCErr DMMCStack::InitStackAfterUnlockSMST( TAny* aStackP )		
  6572 	{ return( static_cast<DMMCStack *>(aStackP)->InitStackAfterUnlockSM() ); }
  6573 
  6574 TMMCErr DMMCStack::AcquireStackSMST( TAny* aStackP )
  6575 	{ return( static_cast<DMMCStack *>(aStackP)->AcquireStackSM() ); }
  6576 
  6577 TMMCErr DMMCStack::CheckStackSMST( TAny* aStackP )
  6578 	{ return( static_cast<DMMCStack *>(aStackP)->CheckStackSM() ); }
  6579 
  6580 TMMCErr DMMCStack::ModifyCardCapabilitySMST( TAny* aStackP )
  6581 	{ return( static_cast<DMMCStack *>(aStackP)->ModifyCardCapabilitySM() ); }
  6582 
  6583 TMMCErr DMMCStack::AttachCardSMST( TAny* aStackP )
  6584 	{ return( static_cast<DMMCStack *>(aStackP)->AttachCardSM() ); }
  6585 
  6586 TMMCErr DMMCStack::ExecCommandSMST( TAny* aStackP )
  6587 	{ return( static_cast<DMMCStack *>(aStackP)->ExecCommandSM() ); }
  6588 
  6589 TMMCErr DMMCStack::IssueCommandCheckResponseSMST(TAny* aStackP)
  6590 	{ return( static_cast<DMMCStack *>(aStackP)->IssueCommandCheckResponseSM() ); }
  6591 
  6592 TMMCErr DMMCStack::PollGapTimerSMST( TAny* aStackP )
  6593 	{ return( static_cast<DMMCStack *>(aStackP)->PollGapTimerSM() ); }
  6594 
  6595 TMMCErr DMMCStack::RetryGapTimerSMST( TAny* aStackP )
  6596 	{ return( static_cast<DMMCStack *>(aStackP)->RetryGapTimerSM() ); }
  6597 
  6598 TMMCErr DMMCStack::ProgramTimerSMST(TAny *aStackP)
  6599 	{ return static_cast<DMMCStack *>(aStackP)->ProgramTimerSM(); }
  6600 
  6601 TMMCErr DMMCStack::GoIdleSMST( TAny* aStackP )
  6602 	{ return( static_cast<DMMCStack *>(aStackP)->GoIdleSM() ); }
  6603 
  6604 TMMCErr DMMCStack::CheckLockStatusSMST( TAny* aStackP )
  6605 	{ return( static_cast<DMMCStack *>(aStackP)->CheckLockStatusSM() ); }
  6606 
  6607 TMMCErr DMMCStack::CIMAutoUnlockSMST( TAny* aStackP )
  6608 	{ return( static_cast<DMMCStack *>(aStackP)->CIMAutoUnlockSM() ); }
  6609 
  6610 TMMCErr DMMCStack::ExecSleepCommandSMST( TAny* aStackP )
  6611 	{ return( static_cast<DMMCStack *>(aStackP)->ExecSleepCommandSM() ); }
  6612 
  6613 TMMCErr DMMCStack::ExecAwakeCommandSMST( TAny* aStackP )
  6614 	{ return( static_cast<DMMCStack *>(aStackP)->ExecAwakeCommandSM() ); }
  6615 //
  6616 // Static interfaces to ASSP layer SM functions
  6617 //
  6618 TMMCErr DMMCStack::DoPowerUpSMST( TAny* aStackP )
  6619 	{ return( static_cast<DMMCStack *>(aStackP)->DoPowerUpSM() ); }
  6620 
  6621 TMMCErr DMMCStack::InitClockOnSMST( TAny* aStackP )
  6622 	{ return( static_cast<DMMCStack *>(aStackP)->InitClockOnSM() ); }
  6623 
  6624 EXPORT_C TMMCErr DMMCStack::IssueMMCCommandSMST( TAny* aStackP )
  6625 	{ return( static_cast<DMMCStack *>(aStackP)->IssueMMCCommandSM() ); }
  6626 
  6627 TMMCErr DMMCStack::DetermineBusWidthAndClockSMST( TAny* aStackP )
  6628 	{ return( static_cast<DMMCStack *>(aStackP)->DetermineBusWidthAndClockSM() ); }
  6629 
  6630 TMMCErr DMMCStack::ConfigureHighSpeedSMST( TAny* aStackP )
  6631 	{ return( static_cast<DMMCStack *>(aStackP)->ConfigureHighSpeedSM() ); }
  6632 
  6633 TMMCErr DMMCStack::ExecSwitchCommandST( TAny* aStackP )
  6634 	{ return( static_cast<DMMCStack *>(aStackP)->ExecSwitchCommand() ); }
  6635 
  6636 TMMCErr DMMCStack::SwitchToLowVoltageSMST( TAny* aStackP )
  6637 	{ return( static_cast<DMMCStack *>(aStackP)->SwitchToLowVoltageSM() ); }
  6638 
  6639 TMMCErr DMMCStack::LowVoltagePowerupTimerSMST(TAny *aStackP)
  6640 	{ return static_cast<DMMCStack *>(aStackP)->LowVoltagePowerupTimerSM(); }
  6641 
  6642 TMMCErr DMMCStack::ExecBusTestSMST( TAny* aStackP )
  6643 	{ return( static_cast<DMMCStack *>(aStackP)->ExecBusTestSM() ); }
  6644 
  6645 TMMCErr DMMCStack::DoWakeUpSMST( TAny* aStackP )
  6646 	{ 	
  6647 	MDoWakeUp* dowakeup = NULL;
  6648 	static_cast<DMMCStack *>(aStackP)->GetInterface(KInterfaceDoWakeUpSM, (MInterface*&) dowakeup);
  6649 	if (dowakeup)
  6650 		{
  6651 		return dowakeup->DoWakeUpSM();
  6652 		}
  6653 	else
  6654 		{
  6655 		// Interface not supported at PSL Level
  6656 		return KMMCErrNotSupported;
  6657 		}
  6658 	}
  6659 
  6660 
  6661 EXPORT_C DMMCSession* DMMCStack::AllocSession(const TMMCCallBack& aCallBack) const
  6662 /**
  6663 * Factory function to create DMMCSession derived object.  Non-generic MMC
  6664 * controllers can override this to generate more specific objects.
  6665 * @param aCallBack Callback function to notify the client that a session has completed
  6666 * @return A pointer to the new session
  6667 */
  6668 	{
  6669 	OstTraceFunctionEntry1( DMMCSTACK_ALLOCSESSION_ENTRY, this );
  6670 	return new DMMCSession(aCallBack);
  6671 	}
  6672 
  6673 EXPORT_C void DMMCStack::Dummy1() {}
  6674 
  6675 /**
  6676  * Calls the PSL-implemented function SetBusWidth() if the bus width has changed
  6677  *
  6678  */
  6679 void DMMCStack::DoSetBusWidth(TUint32 aBusWidth)
  6680 	{
  6681 	OstTraceFunctionEntryExt( DMMCSTACK_DOSETBUSWIDTH_ENTRY, this );
  6682 	if (iBody->iCurrentSelectedBusWidth != aBusWidth)
  6683 		{
  6684 		iBody->iCurrentSelectedBusWidth = aBusWidth;
  6685 		SetBusWidth(aBusWidth);
  6686 		}
  6687 	OstTraceFunctionExit1( DMMCSTACK_DOSETBUSWIDTH_EXIT, this );
  6688 	}
  6689 
  6690 /**
  6691  * Sets iConfig.iBusConfig.iBusClock - which the PSL SHOULD use to set the clock before every command.
  6692  *
  6693  * Some PSLs, however, may only change the clock when SetBusConfigDefaults() is called, 
  6694  * so if the clock has changed, SetBusConfigDefaults() is called
  6695  *
  6696  * @param aClock The requested clock frequency in Kilohertz
  6697  */
  6698 void DMMCStack::DoSetClock(TUint32 aClock)
  6699 	{
  6700 	OstTraceFunctionEntryExt( DMMCSTACK_DOSETCLOCK_ENTRY, this );
  6701 	iConfig.iBusConfig.iBusClock = aClock;
  6702 
  6703 	if (iPoweredUp&&(iBody->iCurrentSelectedClock != aClock))
  6704 		{
  6705 		iBody->iCurrentSelectedClock = aClock;
  6706 		SetBusConfigDefaults(iConfig.iBusConfig, aClock);
  6707 		}
  6708 	OstTraceFunctionExit1( DMMCSTACK_DOSETCLOCK_EXIT, this );
  6709 	}
  6710 
  6711 
  6712 TUint DMMCStack::MaxTranSpeedInKilohertz(const TMMCard& aCard) const
  6713 	{
  6714 	OstTraceFunctionEntry1( DMMCSTACK_MAXTRANSPEEDINKILOHERTZ_ENTRY, this );
  6715 	TUint32 highSpeedClock = aCard.HighSpeedClock();
  6716 	TUint ret = highSpeedClock ? highSpeedClock : aCard.MaxTranSpeedInKilohertz(); 
  6717 	OstTraceFunctionExitExt( DMMCSTACK_MAXTRANSPEEDINKILOHERTZ_EXIT, this, ret );
  6718 	return ret;
  6719 	}
  6720 
  6721 
  6722 
  6723 EXPORT_C void DMMCStack::SetBusWidth(TUint32 /*aBusWidth*/)
  6724 	{
  6725 	}
  6726 
  6727 EXPORT_C void DMMCStack::MachineInfo(TDes8& /*aMachineInfo*/)
  6728 	{
  6729 	}
  6730 
  6731 TBusWidth DMMCStack::BusWidthEncoding(TInt aBusWidth) const
  6732 /**
  6733  * Returns the bus width as a TBusWidth given a card's bus width 
  6734  * expressed as an integer (1,4 or 8)
  6735  * @return the bus width encoded as a TBusWidth
  6736  */
  6737 	{
  6738 	OstTraceFunctionEntryExt( DMMCSTACK_BUSWIDTHENCODING_ENTRY, this );
  6739 	TBusWidth busWidth = EBusWidth1;
  6740 
  6741 	switch(aBusWidth)
  6742 		{
  6743 		case 8: 
  6744 			busWidth =  EBusWidth8; 
  6745 			break;
  6746 		case 4: 
  6747 			busWidth =  EBusWidth4; 
  6748 			break;
  6749 		case 1: 
  6750 		case 0: 
  6751 			busWidth =  EBusWidth1; 
  6752 			break;
  6753 		default:
  6754 			DMMCSocket::Panic(DMMCSocket::EMMCBadBusWidth);
  6755 
  6756 		}
  6757 	OstTraceFunctionExitExt( DMMCSTACK_BUSWIDTHENCODING_EXIT, this, ( TUint )&( busWidth ) );
  6758 	return busWidth;
  6759 	}
  6760 
  6761 /**
  6762  * class DMMCSocket 
  6763  */
  6764 EXPORT_C DMMCSocket::DMMCSocket(TInt aSocketNumber, TMMCPasswordStore* aPasswordStore)
  6765 /**
  6766  * Constructs a DMMCSocket class
  6767  * @param aSocketNumber the socket ID
  6768  * @param aPasswordStore pointer to the password store
  6769  */
  6770 	:DPBusSocket(aSocketNumber),
  6771 	iPasswordStore(aPasswordStore)
  6772 	{
  6773 	OstTraceFunctionEntryExt( DMMCSOCKET_DMMCSOCKET_ENTRY, this );
  6774 	}
  6775 
  6776 TInt DMMCSocket::TotalSupportedCards()
  6777 /**
  6778  * Returns the total number of MMC slots supported by the socket.
  6779  * @return The number of MMC slots supported by the socket
  6780  */
  6781 	{
  6782 	OstTraceFunctionEntry1( DMMCSOCKET_TOTALSUPPORTEDCARDS_ENTRY, this );
  6783 	OstTraceFunctionExitExt( DMMCSOCKET_TOTALSUPPORTEDCARDS_EXIT, this, iMachineInfo.iTotalSockets );
  6784 	return iMachineInfo.iTotalSockets;
  6785 	}
  6786 
  6787 
  6788 // -------- Password store management --------
  6789 
  6790 //
  6791 // The persistent file is a contiguous sequence of entries.
  6792 // An entry format is [CID@16 | PWD_LEN@4 | PWD@PWD_LEN].
  6793 // CID and PWD_LEN are both stored in big endian format.
  6794 //
  6795 
  6796 TInt DMMCSocket::PrepareStore(TInt aBus, TInt aFunc, TLocalDrivePasswordData &aData)
  6797 /**
  6798  * Called from media driver before CMD42 session engaged, in kernel server context
  6799  * so that mappings can be allocated or deallocated.
  6800  * 
  6801  * Using zero-length passwords for MMC operations is disallowed by this function.
  6802  * Locking with and clearing a null password is failed with KErrAccessDenied.
  6803  * If the drive is already mounted, then TBusLocalDrive::Unlock() will fail with
  6804  * KErrAlreadyExists.  Otherwise, this function will fail with KErrLocked, which
  6805  * is translated to KErrAccessDenied in Unlock(), in the same way as unlocking
  6806  * a locked card with the wrong password
  6807  * 
  6808  * @param aBus The card to be unlocked.
  6809  * @param aFunc The operation to perform (EPasswordLock, EPasswordUnlock, EPasswordClear).
  6810  * @param aData TLocalDrivePasswordData reference containing the password
  6811  * @return KErrAccessDenied An attempt to lock or clear was made with a NULL password.
  6812  * @return KErrLocked An an attempt to unlock was made with a NULL password.
  6813  * @return KErrNone on success
  6814  */
  6815 	{
  6816 	OstTraceExt3(TRACE_FLOW, DMMCSOCKET_PREPARESTORE_ENTRY, "DMMCSocket::PrepareStore;aBus=%d;aFunc=%d;this=%x", aBus, aFunc, (TUint) this);
  6817 	TInt r = 0;
  6818 
  6819 	TMMCard *card=iStack->CardP(aBus);
  6820 	__ASSERT_ALWAYS(card, Panic(EMMCSessionNoPswdCard));
  6821 	const TCID &cid = card->CID();
  6822 
  6823 	switch (aFunc)
  6824 		{
  6825 	case DLocalDrive::EPasswordLock:
  6826 		{
  6827 		TMediaPassword newPwd = *aData.iNewPasswd;
  6828 
  6829 		if (newPwd.Length() == 0)
  6830 			r = KErrAccessDenied;
  6831 		else
  6832 			r = PasswordControlStart(cid, aData.iStorePasswd ? &newPwd : NULL);
  6833 		}
  6834 		break;
  6835 
  6836 	case DLocalDrive::EPasswordUnlock:
  6837 		{
  6838 		TMediaPassword curPwd = *aData.iOldPasswd;
  6839 
  6840 		if (curPwd.Length() == 0)
  6841 			r = KErrLocked;
  6842 		else
  6843 			r = PasswordControlStart(cid, aData.iStorePasswd ? &curPwd : NULL);
  6844 		}
  6845 		break;
  6846 
  6847 	case DLocalDrive::EPasswordClear:
  6848 		{
  6849 		TMediaPassword curPwd = *aData.iOldPasswd;
  6850 
  6851 		if (curPwd.Length() == 0)
  6852 			r = KErrAccessDenied;
  6853 		else
  6854 			r = PasswordControlStart(cid, aData.iStorePasswd ? &curPwd : NULL);
  6855 		}
  6856 		break;
  6857 
  6858 	default:
  6859 		Panic(EMMCSessionPswdCmd);
  6860 		break;
  6861 		}
  6862 
  6863 	OstTraceFunctionExitExt( DMMCSOCKET_PREPARESTORE_EXIT, this, r );
  6864 	return r;
  6865 	}
  6866 
  6867 
  6868 TInt DMMCSocket::PasswordControlStart(const TCID &aCID, const TMediaPassword *aPWD)
  6869 /**
  6870  * Remove any non-validated mappings from the store, and allocate a binding for
  6871  * the card's CID if necessary.
  6872  * 
  6873  * s = source (current) password stored; t = target (new) password should be stored
  6874  * f = failure
  6875  * 
  6876  * t is equivalent to iMPTgt.Length() > 0, which is used by PasswordControlEnd().
  6877  * 
  6878  * The target password is not stored in the store at this point, but in the stack.
  6879  * This leaves any existing mapping which can be used for recovery if the operation
  6880  * fails.  This means the user does not have to re-enter the right password after
  6881  * trying to unlock a card with the wrong password.
  6882  * 
  6883  * See PasswordControlEnd() for recovery policy.
  6884  */
  6885 	{
  6886 	OstTraceFunctionEntry1( DMMCSOCKET_PASSWORDCONTROLSTART_ENTRY, this );
  6887 	TInt r = KErrNone;							// error code
  6888 
  6889 	TBool changed = EFalse;						// compress store if changed
  6890 
  6891 	TBuf8<KMMCCIDLength> cid;					// convert to TBuf8<> for comparison
  6892 	cid.SetLength(KMMCCIDLength);
  6893 	aCID.Copy(&cid[0]);
  6894 
  6895 	TBool s = EFalse;							// source password (current mapping)
  6896 	TBool t = aPWD != NULL;						// target pasword (new value for mapping)
  6897 
  6898 	// remove any bindings which were not validated.  This is all non EStValid
  6899 	// bindings - the previous operation could have failed before CMD42 was sent,
  6900 	// in which case its state would be EStPending, not EStInvalid.
  6901 
  6902 	// an inefficiency exists where an invalid binding for the target CID exists.
  6903 	// This could be reused instead of being deallocated and reallocated.  This
  6904 	// situation would occur if the user inserted a card whose password was not
  6905 	// known to the machine, unlocked it with the wrong password and tried again.
  6906 	// The case is rare and the cost is run-time speed, which is not noticeable,
  6907 	// The run-time memory usage is equivalent, so it is probably not worth the
  6908 	// extra rom bytes and logic.
  6909 
  6910 	for (TInt i = 0; i < iPasswordStore->iStore->Count(); )
  6911 		{
  6912 		if ((*iPasswordStore->iStore)[i].iState != TMapping::EStValid)
  6913 			{
  6914 			iPasswordStore->iStore->Remove(i);	// i becomes index for next item
  6915 			changed = ETrue;
  6916 			}
  6917 		else
  6918 			{
  6919 			if ((*iPasswordStore->iStore)[i].iCID == cid)
  6920 				s = ETrue;
  6921 			++i;
  6922 			}
  6923 		}
  6924 
  6925 	if (! t)
  6926 		iStack->iMPTgt.Zero();
  6927 	else
  6928 		{
  6929 		iStack->iMPTgt = *aPWD;
  6930 
  6931 		if (!s)
  6932 			{
  6933 			TMediaPassword mp;					// empty, to indicate !s
  6934 			if ((r = iPasswordStore->InsertMapping(aCID, mp, TMapping::EStPending)) != KErrNone)
  6935 			    {
  6936 				OstTraceFunctionExitExt( DMMCSOCKET_PASSWORDCONTROLSTART_EXIT1, this, r );
  6937 				return r;
  6938 			    }
  6939 
  6940 			changed = ETrue;
  6941 			}
  6942 		}
  6943 
  6944 	if (changed)
  6945 		iPasswordStore->iStore->Compress();
  6946 
  6947 	OstTraceFunctionExitExt( DMMCSOCKET_PASSWORDCONTROLSTART_EXIT2, this, r );
  6948 	return r;
  6949 	}
  6950 
  6951 
  6952 
  6953 void DMMCSocket::PasswordControlEnd(DMMCSession *aSessP, TInt aResult)
  6954 /**
  6955  * called by DMMCStack::SchedCompletionPass() after CMD42 has completed to
  6956  * update internal store.  This function does not run in ks context and so
  6957  * can only invalidate bindings for later removal in PasswordControlStart().
  6958  * 
  6959  * s = source (current) password stored; t = target (new) password should be stored
  6960  * f = failure
  6961  * 
  6962  * If the operation fails, then a recovery policy is used so the user does
  6963  * not lose the good current binding and have to re-enter the password.
  6964  * '
  6965  * f = 0					f = 1
  6966  * 				T						T
  6967  * 			0		1				0		1
  6968  * 	S	0	N		V		S	0	N		I
  6969  * 		1	W		V			1	R		R
  6970  * 
  6971  * 	N	nothing		V	validate	W	wipe
  6972  * 	I	invalidate	R	restore
  6973  * '
  6974  * See PasswordControlStart() for details of how store set up.
  6975  */
  6976 	{
  6977 	OstTraceFunctionEntryExt( DMMCSOCKET_PASSWORDCONTROLEND_ENTRY, this );
  6978 	// autounlock is a special case because the PasswordControlStart() will
  6979 	// not have been called (the CID is not known in ks context.)  The mapping
  6980 	// for this specific card is removed on failure, because it is the current
  6981 	// mapping that is definitely wrong.
  6982 
  6983 	TBuf8<KMMCCIDLength> cid;					// convert to TBuf8<> for comparison
  6984 	cid.SetLength(KMMCCIDLength);
  6985 	aSessP->CardP()->CID().Copy(&cid[0]);
  6986 
  6987 	if (aSessP == &iStack->iAutoUnlockSession)
  6988 		{
  6989 		TBool changed = EFalse;						// compress store if changed
  6990 
  6991 		for (TInt j = 0; j < iPasswordStore->iStore->Count(); )
  6992 			{
  6993 			TMapping &mp = (*iPasswordStore->iStore)[j];
  6994 			if (mp.iCID == cid)
  6995 				{
  6996 				mp.iState = (aResult == KErrNone ? TMapping::EStValid : TMapping::EStInvalid);
  6997 				if(mp.iState == TMapping::EStInvalid)
  6998 					{
  6999 					iPasswordStore->iStore->Remove(j);
  7000 					changed = ETrue;
  7001 					}
  7002 				else
  7003 					{
  7004 					j++;
  7005 					}
  7006 				}
  7007 			else
  7008 				{
  7009 				j++;
  7010 				}
  7011 			}
  7012 
  7013 		if (changed)
  7014 			iPasswordStore->iStore->Compress();
  7015 		}
  7016 	else
  7017 		{
  7018 		const TMediaPassword &mpTgt = iStack->iMPTgt;
  7019 		TBool s = EFalse;						// default value in case no mapping
  7020 		TBool t = mpTgt.Length() > 0;
  7021 		TBool f = (aResult != KErrNone);
  7022 
  7023 		TMapping mp, *pmp;						// get mapping to mutate
  7024 		mp.iCID = cid;
  7025 		TInt psn = iPasswordStore->iStore->Find(mp, iPasswordStore->iIdentityRelation);
  7026 		if (psn == KErrNotFound)
  7027 			{
  7028 			OstTraceFunctionExit1( DMMCSOCKET_PASSWORDCONTROLEND_EXIT1, this );
  7029 			return;
  7030 			}
  7031 		else
  7032 			{
  7033 			pmp = &(*iPasswordStore->iStore)[psn];
  7034 			s = pmp->iPWD.Length() > 0;
  7035 			}
  7036 
  7037 		if (f)
  7038 			{
  7039 			if (s)		// s & ~f
  7040 				pmp->iState = TMapping::EStValid;		// restore
  7041 			else
  7042 				{
  7043 				if (t)	// ~s & t & f 
  7044 					pmp->iState = TMapping::EStInvalid;	// invalidate
  7045 				}
  7046 			}
  7047 		else
  7048 			{
  7049 			if (t)		// t & ~f
  7050 				{
  7051 				pmp->iState = TMapping::EStValid;		// validate
  7052 				pmp->iPWD = mpTgt;
  7053 				}
  7054 			else
  7055 				{
  7056 				if (s)	// s & ~t & ~f
  7057 					pmp->iState = TMapping::EStInvalid;	// wipe
  7058 				}
  7059 			}	// else (f)
  7060 		}	// else if (aSessP == &iStack->iAutoUnlockSession)
  7061 	OstTraceFunctionExit1( DMMCSOCKET_PASSWORDCONTROLEND_EXIT2, this );
  7062 	}
  7063 
  7064 
  7065 TMMCPasswordStore::TMMCPasswordStore()
  7066 /**
  7067  * Contructor
  7068  */
  7069 	: iIdentityRelation(TMMCPasswordStore::CompareCID)
  7070 	{
  7071 	OstTraceFunctionEntry1( TMMCPASSWORDSTORE_TMMCPASSWORDSTORE_ENTRY, this );
  7072 	}
  7073 
  7074 TInt TMMCPasswordStore::Init()
  7075 /**
  7076  * Initialises the password store and allocates resources.
  7077  * @return KErrNone if successful, standard error code otherwise.
  7078  */
  7079 	{
  7080 	OstTraceFunctionEntry1( TMMCPASSWORDSTORE_INIT_ENTRY, this );
  7081 	// We don't have a destructor yet as this object lasts forever
  7082 	iStore = new RArray<TMapping>(4, _FOFF(TMapping, iCID));
  7083 	if(!iStore)
  7084 	    {
  7085 		OstTraceFunctionExitExt( TMMCPASSWORDSTORE_INIT_EXIT1, this, KErrNoMemory );
  7086 		return KErrNoMemory;
  7087 	    }
  7088 	OstTraceFunctionExitExt( TMMCPASSWORDSTORE_INIT_EXIT2, this, KErrNone );
  7089 	return KErrNone;
  7090 	}
  7091 
  7092 EXPORT_C TBool TMMCPasswordStore::IsMappingIncorrect(const TCID& aCID, const TMediaPassword& aPWD)
  7093 /**
  7094  * Returns true if the password is definitely incorrect, i.e. if a valid entry with a
  7095  * different password exists.  Returns false if correct (because the mapping matches,)
  7096  * or if cannot tell (because no valid mapping.)
  7097  */
  7098 	{
  7099 	OstTraceFunctionEntry1( TMMCPASSWORDSTORE_ISMAPPINGINCORRECT_ENTRY, this );
  7100 	TMapping* pmp = FindMappingInStore(aCID);
  7101 	TBool ret = pmp != 0 && pmp->iState == TMapping::EStValid && pmp->iPWD.Compare(aPWD) != 0;
  7102 	OstTraceFunctionExitExt( TMMCPASSWORDSTORE_ISMAPPINGINCORRECT_EXIT, this, ret );
  7103 	return ret;
  7104 	}
  7105 
  7106 TMapping *TMMCPasswordStore::FindMappingInStore(const TCID &aCID)
  7107 /**
  7108  * return pointer to aCID mapping in store or NULL if not found
  7109  */
  7110 	{
  7111 	OstTraceFunctionEntry1( TMMCPASSWORDSTORE_FINDMAPPINGINSTORE_ENTRY, this );
  7112 	TMapping *pmp = NULL;
  7113 	TMapping mp;								// 8 + 16 + 8 + 16 + 4 bytes
  7114 	mp.iCID.SetLength(KMMCCIDLength);
  7115 	aCID.Copy(&mp.iCID[0]);
  7116 
  7117 	TInt psn=iStore->Find(mp, iIdentityRelation);
  7118 	if(psn!=KErrNotFound)
  7119 		{
  7120 		pmp = &(*iStore)[psn];
  7121 		}
  7122 	OstTraceFunctionExitExt( TMMCPASSWORDSTORE_FINDMAPPINGINSTORE_EXIT, this, ( TUint )( pmp ) );
  7123 	return pmp;
  7124 	}
  7125 
  7126 TInt TMMCPasswordStore::InsertMapping(const TCID &aCID, const TMediaPassword &aPWD, TMapping::TState aState)
  7127 /**
  7128  * Ensures that a mapping from aCID to aPWD exists in the store.  If an
  7129  * existing entry does not exist to mutate, then insert a new one.  This
  7130  * may cause an allocation, depending on the granularity and count.
  7131  * 
  7132  * If the CID is already bound to something in the store, then this operation
  7133  * is a binary search, otherwise it may involve kernel heap allocation.
  7134  */
  7135 	{
  7136 	OstTraceFunctionEntry1( TMMCPASSWORDSTORE_INSERTMAPPING_ENTRY, this );
  7137 	TInt r = KErrNone;
  7138 	TMapping mpN;
  7139 	mpN.iCID.SetLength(KMMCCIDLength);
  7140 	aCID.Copy(&mpN.iCID[0]);					// copies from aCID into buffer.
  7141 
  7142 	TInt psn = iStore->Find(mpN, iIdentityRelation);
  7143 	if(psn == KErrNotFound)
  7144 		{
  7145 		mpN.iPWD.Copy(aPWD);
  7146 		mpN.iState = aState;
  7147 		r=iStore->Insert(mpN, iStore->Count());
  7148 		}
  7149 	else
  7150 		{
  7151 		TMapping &mpE = (*iStore)[psn];
  7152 		mpE.iPWD.Copy(aPWD);
  7153 		mpE.iState = aState;
  7154 		r = KErrNone;
  7155 		}
  7156 
  7157 	OstTraceFunctionExitExt( TMMCPASSWORDSTORE_INSERTMAPPING_EXIT, this, r );
  7158 	return r;
  7159 	}
  7160 
  7161 TInt TMMCPasswordStore::PasswordStoreLengthInBytes()
  7162 /**
  7163  * virtual from DPeriphBusController, kern exec
  7164  * return number of bytes needed for persistent file representation
  7165  * of the password store
  7166  */
  7167 	{
  7168 	OstTraceFunctionEntry1( TMMCPASSWORDSTORE_PASSWORDSTORELENGTHINBYTES_ENTRY, this );
  7169 	TInt sz = 0;
  7170 
  7171 	for (TInt i = 0; i < iStore->Count(); ++i)
  7172 		{
  7173 		const TMapping &mp = (*iStore)[i];
  7174 		if (mp.iState == TMapping::EStValid)
  7175 			sz += KMMCCIDLength + sizeof(TInt32) + mp.iPWD.Length();
  7176 		}
  7177 
  7178 	OstTraceFunctionExitExt( TMMCPASSWORDSTORE_PASSWORDSTORELENGTHINBYTES_EXIT, this, sz );
  7179 	return sz;
  7180 	}
  7181 
  7182 TBool TMMCPasswordStore::ReadPasswordData(TDes8 &aBuf)
  7183 /**
  7184  * virtual from DPeriphBusController, kern exec
  7185  * fills descriptor with persistent representation of password store
  7186  * data.  aBuf is resized to contain exactly the password data from
  7187  * the store.  If its maximum length is not enough then KErrOverflow
  7188  * is returned and aBuf is not mutated.
  7189  */
  7190 	{
  7191 	OstTraceFunctionEntry1( TMMCPASSWORDSTORE_READPASSWORDDATA_ENTRY, this );
  7192 	TInt r=KErrNone;										// error code
  7193 
  7194 	if (PasswordStoreLengthInBytes() > aBuf.MaxLength())
  7195 		r = KErrOverflow;
  7196 	else
  7197 		{
  7198 		aBuf.Zero();
  7199 		for (TInt i = 0; i < iStore->Count(); ++i)
  7200 			{
  7201 			const TMapping &mp = (*iStore)[i];
  7202 
  7203 			if (mp.iState == TMapping::EStValid)
  7204 				{
  7205 				aBuf.Append(mp.iCID);
  7206 
  7207 				TUint8 lenBuf[sizeof(TInt32)];		// length, big-endian
  7208 				TMMC::BigEndian4Bytes(lenBuf, TInt32(mp.iPWD.Length()));
  7209 				aBuf.Append(&lenBuf[0], sizeof(TInt32));
  7210 
  7211 				aBuf.Append(mp.iPWD);
  7212 				}
  7213 			}
  7214 
  7215 		r = KErrNone;
  7216 		}
  7217 
  7218 	OstTraceFunctionExitExt( TMMCPASSWORDSTORE_READPASSWORDDATA_EXIT, this, r );
  7219 	return r;
  7220 	}
  7221 
  7222 
  7223 TInt TMMCPasswordStore::WritePasswordData(TDesC8 &aBuf)
  7224 /**
  7225  * virtual from DPeriphBusController, kern server
  7226  * replace current store with data from persistent representation in aBuf.
  7227  */
  7228 	{
  7229 	OstTraceFunctionEntry1( TMMCPASSWORDSTORE_WRITEPASSWORDDATA_ENTRY, this );
  7230 	// should only be called at boot up, but remove chance of duplicate entries
  7231 	iStore->Reset();
  7232 
  7233 	TInt iBIdx;									// buffer index
  7234 
  7235 	// check buffer integrity
  7236 	
  7237 	TBool corrupt = EFalse;						// abort flag
  7238 	for (iBIdx = 0; iBIdx < aBuf.Length(); )
  7239 		{
  7240 		// enough raw data for CID, PWD_LEN and 1 byte of PWD
  7241 		corrupt = TUint(aBuf.Length() - iBIdx) < KMMCCIDLength + sizeof(TUint32) + 1;
  7242 		if (corrupt)
  7243 			break;
  7244 		
  7245 		// PWD_LEN is valid and enough raw data left for PWD
  7246 		iBIdx += KMMCCIDLength;
  7247 		const TInt32 pwd_len(TMMC::BigEndian32(&aBuf[iBIdx]));
  7248 		corrupt = !(
  7249 				(pwd_len <= TInt32(KMaxMediaPassword))
  7250 			&&	aBuf.Length() - iBIdx >= TInt(sizeof(TUint32)) + pwd_len );
  7251 		if (corrupt)
  7252 			break;
  7253 		
  7254 		// skip over PWD_LEN and PWD to next entry
  7255 		iBIdx += sizeof(TInt32) + pwd_len;
  7256 		}
  7257 
  7258 	if (corrupt)
  7259 	    {
  7260 		OstTraceFunctionExitExt( TMMCPASSWORDSTORE_WRITEPASSWORDDATA_EXIT1, this, KErrCorrupt );
  7261 		return KErrCorrupt;
  7262 	    }
  7263 
  7264 	// Build the store from the entries in the buffer.
  7265 	TInt r = KErrNone;							// error code
  7266 	for (iBIdx = 0; r == KErrNone && iBIdx < aBuf.Length(); )
  7267 		{
  7268 		TPtrC8 pCID(&aBuf[iBIdx], KMMCCIDLength);	// CID
  7269 		const TCID cid(pCID.Ptr());
  7270 
  7271 		const TInt32 pwd_len(TMMC::BigEndian32(&aBuf[iBIdx + KMMCCIDLength]));
  7272 		TMediaPassword pwd;
  7273 		pwd.Copy(&aBuf[iBIdx + KMMCCIDLength + sizeof(TInt32)], pwd_len);
  7274 
  7275 		iBIdx += KMMCCIDLength + sizeof(TInt32) + pwd_len;
  7276 		r = InsertMapping(cid, pwd, TMapping::EStValid);
  7277 		}
  7278 
  7279 	// it may be acceptable to use a partially created store, providing the
  7280 	// sections that do exist are valid.  Alternatively, the operation should
  7281 	// atomic from the startup thread's point of view.
  7282 
  7283 	if (r != KErrNone)
  7284 		iStore->Reset();
  7285 
  7286 	OstTraceFunctionExitExt( TMMCPASSWORDSTORE_WRITEPASSWORDDATA_EXIT2, this, r );
  7287 	return r;
  7288 	}
  7289 
  7290 TInt TMMCPasswordStore::CompareCID(const TMapping& aLeft, const TMapping& aRight)
  7291 /**
  7292  * CID Comparason Functions for RArray::Find
  7293  */
  7294 	{
  7295 	OstTraceFunctionEntry0( TMMCPASSWORDSTORE_COMPARECID_ENTRY );
  7296 	return(aLeft.iCID == aRight.iCID);
  7297 	}
  7298 
  7299 void DMMCSocket::InitiatePowerUpSequence()
  7300 /**
  7301  * Initiates a power up sequence on the stack
  7302  */
  7303 	{
  7304 	OstTraceFunctionEntry1( DMMCSOCKET_INITIATEPOWERUPSEQUENCE_ENTRY, this );
  7305 	iStack->PowerUpStack();
  7306 	OstTraceFunctionExit1( DMMCSOCKET_INITIATEPOWERUPSEQUENCE_EXIT, this );
  7307 	}
  7308 
  7309 TBool DMMCSocket::CardIsPresent()
  7310 /**
  7311  * Indicates the presence of a card.
  7312  * @return ETrue if a card is present, EFalse otherwise
  7313  */
  7314 	{
  7315 	OstTraceFunctionEntry1( DMMCSOCKET_CARDISPRESENT_ENTRY, this );
  7316 	TInt r = iStack->HasCardsPresent();
  7317 	OstTraceFunctionExitExt( DMMCSOCKET_CARDISPRESENT_EXIT, this, r );
  7318 	return r;
  7319 	}
  7320 
  7321 void DMMCSocket::AdjustPartialRead(const TMMCard* aCard, TUint32 aStart, TUint32 aEnd, TUint32* aPhysStart, TUint32* aPhysEnd) const
  7322 /**
  7323  * Calculates the minimum range that must be read off a card, an optimisation that takes advantage
  7324  * of the partial read feature found on some cards.  It takes the logical range that the media driver
  7325  * wants to read from the card, and increases it to take into account factors such as FIFO width and
  7326  * minimum DMA transfer size.
  7327  * @param aCard A pointer to the MMC Card
  7328  * @param aStart The required start position
  7329  * @param aEnd The required end position
  7330  * @param aPhysStart The adjusted start position
  7331  * @param aPhysEnd The adjusted end position
  7332  */
  7333 	{
  7334 	OstTraceFunctionEntryExt( DMMCSOCKET_ADJUSTPARTIALREAD_ENTRY, this );
  7335 	iStack->AdjustPartialRead(aCard, aStart, aEnd, aPhysStart, aPhysEnd);
  7336 	OstTraceFunctionExit1( DMMCSOCKET_ADJUSTPARTIALREAD_EXIT, this );
  7337 	}
  7338 
  7339 void DMMCSocket::GetBufferInfo(TUint8** aMDBuf, TInt* aMDBufLen)
  7340 /**
  7341  * Returns the details of the buffer allocated by the socket for data transfer operations.  The buffer
  7342  * is allocated and configured at the variant layer to allow , for example, contiguous pages to be
  7343  * allocated for DMA transfers.
  7344  * @param aMDBuf A pointer to the allocated buffer
  7345  * @param aMDBufLen The length of the allocated buffer
  7346  */
  7347 	{
  7348 	OstTraceFunctionEntryExt( DMMCSOCKET_GETBUFFERINFO_ENTRY, this );
  7349 	iStack->GetBufferInfo(aMDBuf, aMDBufLen);
  7350 	OstTraceFunctionExit1( DMMCSOCKET_GETBUFFERINFO_EXIT, this );
  7351 	}
  7352 
  7353 void DMMCSocket::Reset1()
  7354 /**
  7355  * Resets the socket by powering down the stack.
  7356  * If there are operations in progress (inCritical), this call will be deferred
  7357  * until the operation is complete.  In the case of an emergency power down,
  7358  * this will occur immediately.
  7359  */
  7360 	{
  7361 	OstTraceFunctionEntry1( DMMCSOCKET_RESET1_ENTRY, this );
  7362 	if (iState == EPBusCardAbsent)
  7363 	    {
  7364 	    // Reset is result of card eject!
  7365 	    iStack->iStackState |= KMMCStackStateCardRemoved;
  7366 	    }
  7367 	
  7368 	
  7369 	iStack->PowerDownStack();
  7370 	OstTraceFunctionExit1( DMMCSOCKET_RESET1_EXIT, this );
  7371 	}
  7372 
  7373 void DMMCSocket::Reset2()
  7374 /**
  7375  * Resets the socket in response to a PSU fault or media change.
  7376  * Called after Reset1, gives the opportunity to free upp allocated resources
  7377  */
  7378 	{
  7379 	// No need to do anything here, as the only thing to do is power down the
  7380 	// stack, which is performed in ::Reset1
  7381 	}
  7382 
  7383 TInt DMMCSocket::Init()
  7384 /**
  7385  * Allocates resources and initialises the MMC socket and associated stack object.
  7386  * @return KErrNotReady if no stack has been allocated, standard error code otherwise
  7387  */
  7388 	{
  7389 	OstTraceFunctionEntry1( DMMCSOCKET_INIT_ENTRY, this );
  7390 	__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Init"));
  7391 	
  7392 	GetMachineInfo();
  7393 
  7394 	// We need to make sure the stack is initialised,
  7395 	// as DPBusSocket::Init() will initiate a power up sequence
  7396 	if(iStack == NULL)
  7397 	    {
  7398 		OstTraceFunctionExitExt( DMMCSOCKET_INIT_EXIT1, this, KErrNotReady );
  7399 		return KErrNotReady;
  7400 	    }
  7401 
  7402 	TInt r = iStack->Init();
  7403 	if (r!=KErrNone)
  7404 	    {
  7405 		OstTraceFunctionExitExt( DMMCSOCKET_INIT_EXIT2, this, r );
  7406 		return r;
  7407 	    }
  7408 
  7409 	r = DPBusSocket::Init();
  7410 	if (r!=KErrNone)
  7411 	    {
  7412 		OstTraceFunctionExitExt( DMMCSOCKET_INIT_EXIT3, this, r );
  7413 		return r;
  7414 	    }
  7415 	
  7416 	OstTraceFunctionExitExt( DMMCSOCKET_INIT_EXIT4, this, KErrNone );
  7417 	return KErrNone;
  7418 	}
  7419 
  7420 void DMMCSocket::GetMachineInfo()
  7421 /**
  7422  * Gets the platform specific configuration information.
  7423  * @see TMMCMachineInfo
  7424  */
  7425 	{
  7426 	OstTraceFunctionEntry1( DMMCSOCKET_GETMACHINEINFO_ENTRY, this );
  7427 	// Get machine info from the stack
  7428 	iStack->MachineInfo(iMachineInfo);
  7429 
  7430 	__KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iTotalSockets %u", iMachineInfo.iTotalSockets));
  7431 	__KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iTotalMediaChanges %u", iMachineInfo.iTotalMediaChanges));
  7432 	__KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iTotalPrimarySupplies %u", iMachineInfo.iTotalPrimarySupplies));
  7433 	__KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iSPIMode %u", iMachineInfo.iSPIMode));
  7434 	__KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iBaseBusNumber %u", iMachineInfo.iBaseBusNumber));
  7435 	OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSOCKET_GETMACHINEINFO, "iTotalSockets=%d; iTotalMediaChanges=%d; iTotalPrimarySupplies=%d; iSPIMode=%d; iBaseBusNumber=%d", iMachineInfo.iTotalSockets, iMachineInfo.iTotalMediaChanges, iMachineInfo.iTotalPrimarySupplies, iMachineInfo.iSPIMode, iMachineInfo.iBaseBusNumber );
  7436 	
  7437 	
  7438 	OstTraceFunctionExit1( DMMCSOCKET_GETMACHINEINFO_EXIT, this );
  7439 	}
  7440 
  7441 
  7442 // MMC specific functions
  7443 
  7444 EXPORT_C void DMMCSocket::Panic(TMMCPanic aPanic)
  7445 /**
  7446  * Panic the MMC Controller
  7447  * @param aPanic The panic code
  7448  */
  7449 	{
  7450 	OstTraceFunctionEntry0( DMMCSOCKET_PANIC_ENTRY );
  7451 	_LIT(KPncNm,"PBUS-MMC");
  7452 	Kern::PanicCurrentThread(KPncNm,aPanic);
  7453 	}
  7454 
  7455 EXPORT_C DMMCPsu::DMMCPsu(TInt aPsuNum, TInt aMediaChangedNum)
  7456 /**
  7457  * Constructor for a DMMCPsu object
  7458  * @param aPsuNum The power supply number
  7459  * @param aMediaChangedNum The associated media change number
  7460  */
  7461 	: DPBusPsuBase(aPsuNum, aMediaChangedNum)
  7462 	{
  7463 	OstTraceFunctionEntryExt( DMMCPSU_DMMCPSU_ENTRY, this );
  7464 	
  7465 	iVoltageSetting=0x00ffc000; // Default voltage range - 2.6V to 3.6V (OCR reg. format).
  7466 	OstTraceFunctionExit1( DMMCPSU_DMMCPSU_EXIT, this );
  7467 	}
  7468 
  7469 EXPORT_C TInt DMMCPsu::DoCreate()
  7470 /**
  7471  * Create a DMMCPsu object.
  7472  * This should be overridden at the variant layer to allow interrupts and
  7473  * other variant-specific parameters to be initialised.  The default 
  7474  * implementation does nothing.
  7475  * @return Standard Symbian OS error code.
  7476  */
  7477 	{
  7478 	return KErrNone;
  7479 	}
  7480 
  7481 
  7482 void DMMCPsu::SleepCheck(TAny* aPtr)
  7483 /**
  7484  * Checks if media can be placed in Sleep state 
  7485  * and therefore if VccQ supply can be turned off.
  7486  * 
  7487  * @Param aPtr reference to DMMCPsu Object to be acted upon.
  7488  */
  7489 	{	
  7490 	OstTraceFunctionEntry0( DMMCPSU_SLEEPCHECK_ENTRY );
  7491 	DMMCPsu& self = *static_cast<DMMCPsu*>(aPtr);
  7492 	
  7493 	if (
  7494 		(self.iNotLockedTimeout&&!self.IsLocked()&&++self.iNotLockedCount>self.iNotLockedTimeout) ||
  7495 		(self.iInactivityTimeout&&++self.iInactivityCount>self.iInactivityTimeout)
  7496 	   )
  7497 		{
  7498 		DMMCSocket* socket = static_cast<DMMCSocket*>(self.iSocket);
  7499 		socket->iStack->QSleepStack();
  7500 		}
  7501 	OstTraceFunctionExit0( DMMCPSU_SLEEPCHECK_EXIT );
  7502 	}
  7503 
  7504 EXPORT_C DMMCMediaChange::DMMCMediaChange(TInt aMediaChangeNum)
  7505 /**
  7506  * Constructor for a DMMCMediaChange object
  7507  * @param aMediaChangeNum The media change number
  7508  */
  7509 	: DMediaChangeBase(aMediaChangeNum)
  7510 	{
  7511 	OstTraceFunctionEntryExt( DMMCMEDIACHANGE_DMMCMEDIACHANGE_ENTRY, this );
  7512 	}
  7513 
  7514 EXPORT_C TInt DMMCMediaChange::Create()
  7515 /**
  7516  * Create a DMMCMediaChange object.
  7517  * This should be overridden at the variant layer to allow interrupts and
  7518  * other variant-specific parameters to be initialised.  The base class implementation
  7519  * should be called prior to any variant-specific initialisation.
  7520  * @return Standard Symbian OS error code.
  7521  */
  7522 	{
  7523 	OstTraceFunctionEntry1( DMMCMEDIACHANGE_CREATE_ENTRY, this );
  7524 	TInt r = DMediaChangeBase::Create();
  7525 	OstTraceFunctionExitExt( DMMCMEDIACHANGE_CREATE_EXIT, this, r );
  7526 	return r;
  7527 	}
  7528