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