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