os/kernelhwsrv/kernel/eka/drivers/pbus/mmc/session.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <drivers/mmc.h>
    17 #include "OstTraceDefinitions.h"
    18 #ifdef OST_TRACE_COMPILER_IN_USE
    19 #include "locmedia_ost.h"
    20 #ifdef __VC32__
    21 #pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
    22 #endif
    23 #include "sessionTraces.h"
    24 #endif
    25 
    26 
    27 
    28 //	--------  class DMMCSession  --------
    29 
    30 EXPORT_C DMMCSession::DMMCSession(const TMMCCallBack& aCallBack)
    31 /**
    32  * Constructor - initializes callbacks and timers.
    33  * Once the session has been engaged, the completion of the request is signalled by calling 
    34  * the function provided in aCallback. A session will be completed in this way if it has completed
    35  * normally, an error has occurred or the session has been stopped by this or another client.
    36  * @param aCallBack reference to a TMMCCallback object to be called upon completion.
    37  */
    38 	: iCallBack(aCallBack),
    39 #ifdef __EPOC32__
    40 	iPollTimer(DMMCSession::PollTimerCallBack, this),
    41 	iRetryTimer(DMMCSession::RetryTimerCallBack, this),
    42 	iProgramTimer(DMMCSession::ProgramTimerCallBack, this),
    43 #endif	// #ifdef __EPOC32__
    44 	iConfig()
    45 	{
    46 	OstTraceFunctionEntry1( DMMCSESSION_DMMCSESSION_ENTRY, this );
    47 	}
    48 
    49 EXPORT_C DMMCSession::~DMMCSession()
    50 /**
    51  * Destructor.
    52  */
    53 	{
    54 	OstTraceFunctionEntry1( DUP1_DMMCSESSION_DMMCSESSION_ENTRY, this );
    55 	// Ensure that the stack isn't currently running in another thread's context, otherwise this session won't be 
    56 	// removed from the stack's workset until some time later - by which time the session will have been deleted
    57 	__ASSERT_ALWAYS(!iStackP->StackRunning(), DMMCSocket::Panic(DMMCSocket::EMMCNotInDfcContext));
    58 	Abort();
    59 	UnlockStack();
    60 	OstTraceFunctionExit1( DUP1_DMMCSESSION_DMMCSESSION_EXIT, this );
    61 	}
    62 
    63 EXPORT_C void DMMCSession::SetCard(TMMCard* aCardP)
    64 /**
    65  * Assigns a card to the session. The card pointer would normally be obtained via a call of DMMCStack::CardP(). 
    66  * Assigning a card to the session is the means by which a particular card in the stack is targeted for a 
    67  * particular request. Some requests involve broadcasting to the entire stack. However, the majority involve 
    68  * an individual card at some stage of the process and so an attempt to engage the session before a card has 
    69  * been assigned to it will generally fail straight away. It is possible to change the card assigned to the 
    70  * session as long as this is not attempted while the session is engaged.
    71  * @param aCardP A pointer to the card to be assigned to the session.
    72  */
    73 	{
    74 	OstTraceFunctionEntryExt( DMMCSESSION_SETCARD_ENTRY, this );
    75 	iCardP = aCardP;
    76 	iCID = iCardP->CID();
    77 	OstTraceFunctionExit1( DMMCSESSION_SETCARD_EXIT, this );
    78 	}
    79 
    80 EXPORT_C void DMMCSession::SetupCIMReadBlock(TMMCArgument aDevAddr, TUint32 aLength, TUint8* aMemoryP)
    81 /**
    82  * Sets the session up to perform the CIM_READ_BLOCK macro as outlined by the MMCA. 
    83  * Having set-up the session for this operation, the client must then engage the session before the operation can commence. 
    84  * The CIM_READ_BLOCK macro reads a single block from the card. It starts by setting the block length (CMD16) as specified 
    85  * in 'aLength'. It then reads a single block of data (CMD17) from the card at offset 'aDevAddr' on the card into system 
    86  * memory starting at address 'aMemoryP'.
    87  * @param aDevAddr Contains offset to the block to be read from the card
    88  * @param aLength Block length
    89  * @param aMemoryP host destination address
    90  */
    91 	{
    92 	OstTraceExt4(TRACE_FLOW, DMMCSESSION_SETUPCIMREADBLOCK_ENTRY, "DMMCSession::SetupCIMReadBlock;aDevAddr=%x;aLength=%x;aMemoryP=%x;this=%x", (TUint) aDevAddr, (TUint) aLength, (TUint) aMemoryP, (TUint) this);
    93 	ResetCommandStack();
    94 	FillCommandArgs(aDevAddr, aLength, aMemoryP, aLength);
    95 	iSessionID = ECIMReadBlock;
    96 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMREADBLOCK_EXIT, this );
    97 	}
    98 
    99 EXPORT_C void DMMCSession::SetupCIMWriteBlock(TMMCArgument aDevAddr, TUint32 aLength, TUint8* aMemoryP)
   100 /**
   101  * Set up the session to perform the CIM_WRITE_BLOCK macro as outlined by the MMCA.
   102  * Having set-up the session for this operation, the client must then engage the session before the operation can commence. 
   103  * The CIM_WRITE_BLOCK macro writes a single block to the card. It starts by setting the block length (CMD16) as specified 
   104  * in 'aLength'. It then writes a single block of data (CMD24) to the card at offset 'aDevAddr' on the card reading from system 
   105  * memory starting at address 'aMemoryP'.
   106  * @param aDevAddr Contains offset to the block to be written on the card
   107  * @param aLength Block length
   108  * @param aMemoryP Host source address
   109  */
   110 	{
   111 	OstTraceExt4(TRACE_FLOW, DMMCSESSION_SETUPCIMWRITEBLOCK_ENTRY, "DMMCSession::SetupCIMWriteBlock;aDevAddr=%x;aLength=%x;aMemoryP=%x;this=%x", (TUint) aDevAddr, (TUint) aLength, (TUint) aMemoryP, (TUint) this);
   112 	ResetCommandStack();
   113 	FillCommandArgs(aDevAddr, aLength, aMemoryP, aLength);
   114 	iSessionID = ECIMWriteBlock;
   115 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMWRITEBLOCK_EXIT, this );
   116 	}
   117 
   118 EXPORT_C void DMMCSession::SetupCIMReadMBlock(TMMCArgument aDevAddr, TUint32 aLength, TUint8* aMemoryP, TUint32 aBlkLen)
   119 /**
   120  * Set up the session to perform the CIM_READ_MBLOCK macro as outlined by the MMCA.
   121  * Having set-up the session for this operation, the client must then engage the session before the operation can commence. 
   122  * The CIM_READ_MBLOCK macro reads a series of blocks from the card. It starts by setting the block length (CMD16) as specified 
   123  * in 'aBlkLen'. It then issues the read multiple block command (CMD18) to continually transfer blocks from the card to host 
   124  * starting at offset 'aDevAddr' on the card into system memory starting at address 'aMemoryP'. This continues until 'aLength'
   125  * bytes have been read at which point the Controller issues the stop command (CMD12) to halt the transfer.
   126  * @param aDevAddr Contains offset to the block to be read from the card
   127  * @param aLength Total number of bytes to read.
   128  * @param aMemoryP Host destination address
   129  * @param aBlkLen Block length
   130  */
   131 	{
   132 	OstTraceExt5(TRACE_FLOW, DMMCSESSION_SETUPCIMREADMBLOCK_ENTRY, "DMMCSession::SetupCIMReadMBlock;aDevAddr=%x;aLength=%x;aMemoryP=%x;aBlkLen=%x;this=%x", (TUint) aDevAddr, (TUint) aLength, (TUint) aMemoryP, (TUint) aBlkLen,(TUint) this);
   133 	ResetCommandStack();
   134 	FillCommandArgs(aDevAddr, aLength, aMemoryP, aBlkLen);
   135 	iSessionID = ECIMReadMBlock;
   136 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMREADMBLOCK_EXIT, this );
   137 	}
   138 
   139 EXPORT_C void DMMCSession::SetupCIMWriteMBlock(TMMCArgument aDevAddr, TUint32 aLength, TUint8* aMemoryP, TUint32 aBlkLen)
   140 /**
   141  * Set up the session to perform the CIM_WRITE_MBLOCK macro as outlined by the MMCA.
   142  * Having set-up the session for this operation, the client must then engage the session before the operation can commence. 
   143  * The CIM_WRITE_MBLOCK macro writes a series of blocks to the card. It starts by setting the block length (CMD16) as specified 
   144  * in 'aBlkLen'. It then issues the write multiple block command (CMD25) to continually transfer blocks from host to the card 
   145  * starting at address 'aMemoryP' in system memory and offset 'aDevAddr' on the card.. This continues until 'aLength' bytes have 
   146  * been written at which point the Controller issues the stop command (CMD12) to halt the transfer
   147  * @param aDevAddr Contains offset to the block to be written on the card
   148  * @param aLength Total number of bytes to write.
   149  * @param aMemoryP Host source address
   150  * @param aBlkLen Block length
   151  */
   152 	{
   153 	OstTraceExt5(TRACE_FLOW, DMMCSESSION_SETUPCIMWRITEMBLOCK_ENTRY, "DMMCSession::SetupCIMWriteMBlock;aDevAddr=%x;aLength=%x;aMemoryP=%x;aBlkLen=%x;this=%x", (TUint) aDevAddr, (TUint) aLength, (TUint) aMemoryP, (TUint) aBlkLen,(TUint) this);
   154 	ResetCommandStack();
   155 	FillCommandArgs(aDevAddr, aLength, aMemoryP, aBlkLen);
   156 	iSessionID = ECIMWriteMBlock;
   157 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMWRITEMBLOCK_EXIT, this );
   158 	}
   159 
   160 EXPORT_C void DMMCSession::SetupCIMEraseSector(TMMCArgument aDevAddr, TUint32 aLength)
   161 /**
   162  * Set up the session to perform the CIM_ERASE_SECTOR macro broadly as outlined by the MMCA. 
   163  * However, the macro only performs a sector erase of a contiguous area and doesn't support the un-tagging of particular sectors 
   164  * within the initial tagged area. Having set-up the session for this operation, the client must then engage the session before 
   165  * the operation can commence. 
   166  * The CIM_ERASE_SECTOR macro erases a range of sectors on the card starting at offset 'aDevAddr' on the card and ending at offset 
   167  * 'aDevAdd'+'aLength'. The entire area specified must lie within a single erase group. (The erase group size can be read from the CSD).
   168  * The specified start offset and end offset need not coincide exactly with a sector boundary since the card will ignore LSBs below 
   169  * the sector size. The tag sector start command (CMD32) is first issued setting the address of the first sector to be erased. 
   170  * This is followed by the tag sector end command (CMD33) setting the address of the last sector to be erased. Now that the erase 
   171  * sectors are tagged, the erase command (CMD38) is sent followed by a send status command (CMD13) to read any additional status 
   172  * information from the card.
   173  * @param aDevAddr Contains offset to the first block to be erased
   174  * @param aLength Total number of bytes to erase
   175  */
   176 	{
   177 	OstTraceExt3(TRACE_FLOW, DMMCSESSION_SETUPCIMERASESECTOR_ENTRY, "DMMCSession::SetupCIMEraseSector;aDevAddr=%x;aLength=%x;this=%x", (TUint) aDevAddr, (TUint) aLength, (TUint) this);
   178 	ResetCommandStack();
   179 	FillCommandArgs(aDevAddr, aLength, NULL, 0);
   180 	iSessionID = ECIMEraseSector;
   181 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMERASESECTOR_EXIT, this );
   182 	}
   183 
   184 EXPORT_C void DMMCSession::SetupCIMEraseGroup(TMMCArgument aDevAddr, TUint32 aLength)
   185 /**
   186  * Set up the session to perform the CIM_ERASE_GROUP macro broadly as outlined by the MMCA. 
   187  * However, the macro only performs an erase group erase of a contiguous area and doesn't support the un-tagging of particular 
   188  * erase groups within the initial tagged area. Having set-up the session for this operation, the client must then engage the 
   189  * session before the operation can commence. 
   190  * The CIM_ERASE_GROUP macro erases a range of erase groups on the card starting at offset 'aDevAddr' on the card and ending at 
   191  * offset 'aDevAdd'+'aLength'. The specified start offset and end offset need not coincide exactly with an erase group boundary 
   192  * since the card will ignore LSBs below the erase group size. The tag ease group start command (CMD35) is first issued setting 
   193  * the address of the first erase group to be erased. This is followed by the tag erase group end command (CMD36) setting the 
   194  * address of the last erase group to be erased. Now that the erase groups are tagged, the erase command (CMD38) is sent followed 
   195  * by a send status command (CMD13) to read any additional status information from the card.
   196  * @param aDevAddr Contains offset to the first block to be erased
   197  * @param aLength Total number of bytes to erase
   198  */
   199 	{
   200 	OstTraceExt3(TRACE_FLOW, DMMCSESSION_SETUPCIMERASEGROUP_ENTRY, "DMMCSession::SetupCIMEraseGroup;aDevAddr=%x;aLength=%x;this=%x", (TUint) aDevAddr, (TUint) aLength, (TUint) this);
   201 	ResetCommandStack();
   202 	FillCommandArgs(aDevAddr, aLength, NULL, 0);
   203 	iSessionID = ECIMEraseGroup;
   204 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMERASEGROUP_EXIT, this );
   205 	}
   206 
   207 EXPORT_C void DMMCSession::SetupCIMReadIO(TUint8 aRegAddr, TUint32 aLength, TUint8* aMemoryP)
   208 /** 
   209  * Set up the session to perform the read i/o macro (CMD39).
   210  * This macro reads a stream of bytes from an I/O register on a MultiMediaCard. This makes use of the fast i/o (CMD39) command, 
   211  * reading 'aLength' bytes of data from I/O register 'aRegAddr' on the card into system memory starting at address 'aMemoryP'. 
   212  * Having set-up the session for this operation, the client must then engage the session before the operation can commence. 
   213  * @param aRegAddr Address of IO register
   214  * @param aLength Total number of bytes to read
   215  * @param aMemoryP Host destination address
   216  */
   217 	{
   218 	OstTraceFunctionEntryExt( DMMCSESSION_SETUPCIMREADIO_ENTRY, this );
   219 	ResetCommandStack();
   220 	FillCommandArgs(aRegAddr, aLength, aMemoryP, 0);
   221 	iSessionID = ECIMReadIO;
   222 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMREADIO_EXIT, this );
   223 	}
   224 
   225 EXPORT_C void DMMCSession::SetupCIMWriteIO(TUint8 aRegAddr, TUint32 aLength, TUint8* aMemoryP)
   226 /** 
   227  * Set up the session to perform the write i/o macro (CMD39). 
   228  * This macro writes a stream of bytes to an I/O register on a MultiMediaCard. This makes use of the fast i/o (CMD39) command,
   229  * writing 'aLength' bytes of data to I/O register 'aRegAddr' on the card from system memory starting at address 'aMemoryP'. 
   230  * Having set-up the session for this operation, the client must then engage the session before the operation can commence. 
   231  * @param aRegAddr Address of IO register
   232  * @param aLength Total number of bytes to write
   233  * @param aMemoryP Host source address
   234  */
   235 	{
   236 	OstTraceFunctionEntryExt( DMMCSESSION_SETUPCIMWRITEIO_ENTRY, this );
   237 	ResetCommandStack();
   238 	FillCommandArgs(aRegAddr, aLength, aMemoryP, 0);
   239 	iSessionID = ECIMWriteIO;
   240 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMWRITEIO_EXIT, this );
   241 	}
   242 
   243 EXPORT_C void DMMCSession::SetupCIMLockUnlock(TUint32 aLength, TUint8* aMemoryP)
   244 /**
   245  * Set up the session to perform the lock-unlock macro (CMD42). 
   246  * This macro is used to manage the password protection feature (if supported) on a MultiMediaCard. 
   247  * This same macro is used to lock or unlock a card, set or clear a password or force erase a card.  
   248  * Having set-up the session for the required operation, the client must then engage the session before 
   249  * the operation can commence. 
   250  * The block length (CMD16) as specified in 'aLength' is first set. The lock unlock command (CMD42) is 
   251  * then issued. This command has the same structure as a regular single block write command. 
   252  * A data block is written to the card from system memory starting at address 'aMemoryP'. The transferred 
   253  * data block should contain the password setting mode, the password length and the password data if appropriate.
   254  * @param aLength Block length
   255  * @param aMemoryP Host source address containing password data
   256  */
   257 	{
   258 	OstTraceFunctionEntryExt( DMMCSESSION_SETUPCIMLOCKUNLOCK_ENTRY, this );
   259 	__KTRACE_OPT(KPBUS1, Kern::Printf("ms:slu%08x", aLength));
   260 
   261 	ResetCommandStack();
   262 	FillCommandDesc(ECmdLockUnlock);
   263 	FillCommandArgs(0, aLength, aMemoryP, aLength);
   264 	iSessionID = ECIMLockUnlock;
   265 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMLOCKUNLOCK_EXIT, this );
   266 	}
   267 
   268 EXPORT_C void DMMCSession::SetupCommand(TMMCCommandEnum aCommand, TMMCArgument anArgument)
   269 /** 
   270  * Set up the session to issue a raw command to the card. 
   271  * This raw command function should be used when issuing a known command with or without an argument. 
   272  * Having set-up the session for this operation, the client must then engage this session before 
   273  * the operation can commence.
   274  * @param aCommand Command to be sent
   275  * @param anArgument Associated argument
   276  */
   277 	{
   278 	OstTraceExt3(TRACE_FLOW, DMMCSESSION_SETUPCOMMAND_ENTRY, "DMMCSession::SetupCommand;aCommand=%d;anArgument=%x;this=%x", (TInt) aCommand, (TUint) anArgument, (TUint) this);
   279 	ResetCommandStack();
   280 	FillCommandDesc(aCommand, anArgument);
   281 	iSessionID = ECIMNakedSession;
   282 	OstTraceFunctionExit1( DMMCSESSION_SETUPCOMMAND_EXIT, this );
   283 	}
   284 
   285 EXPORT_C void DMMCSession::SetupRSCommand(TMMCCommandEnum aCommand, TMMCArgument anArgument,
   286 							TUint32 aResponseLength, TMMCCommandTypeEnum aCommandType,
   287 							TMMCResponseTypeEnum aResponseType,
   288 							TUint32 aCommandClass)
   289 /**
   290  * Set up the session to issue a raw command to the card. 
   291  * This raw command function should be used when issuing an unknown command, an argument and an unknown response type.
   292  * Having set-up the session for this operation, the client must then engage this session before the operation can commence.
   293  * @param aCommand
   294  * @param anArgument
   295  * @param aResponseLength
   296  * @param aCommandType
   297  * @param aResponseType
   298  * @param aCommandClass
   299  * @todo Complete the parameter descriptions
   300  */
   301 	{
   302 	OstTraceExt4( TRACE_FLOW, DMMCSESSION_SETUPRSCOMMAND_ENTRY1, "DMMCSession::SetupRSCommand;aCommand=%d;anArgument=%x;aResponseLength=%x;this=%x", (TInt) aCommand, (TUint) anArgument, (TUint) aResponseLength, (TUint) this );
   303 	OstTraceExt4( TRACE_FLOW, DMMCSESSION_SETUPRSCOMMAND_ENTRY2, "DMMCSession::SetupRSCommand;aCommandType=%d;aResponseType=%d;aCommandClass=%x;this=%x", (TInt) aCommandType, (TInt) aResponseType, (TUint) aCommandClass, (TUint) this );
   304 	ResetCommandStack();
   305 	FillCommandDesc(aCommand, anArgument);
   306 	TMMCCommandSpec& cmdSpec = Command().iSpec;
   307 	cmdSpec.iDirection = EDirNone;
   308 
   309 	if( aResponseLength <= KMMCMaxResponseLength )
   310 		cmdSpec.iResponseLength = aResponseLength;
   311 
   312 	if( aCommandType != ECmdTypeUK )
   313 		cmdSpec.iCommandType = aCommandType;
   314 
   315 	if( aResponseType != ERespTypeUnknown )
   316 		cmdSpec.iResponseType = aResponseType;
   317 
   318 	if( aCommandClass != KMMCCmdClassNone )
   319 		cmdSpec.iCommandClass = aCommandClass;
   320 
   321 	iSessionID = ECIMNakedSession;
   322 	OstTraceFunctionExit1( DMMCSESSION_SETUPRSCOMMAND_EXIT, this );
   323 	}
   324 
   325 EXPORT_C void DMMCSession::SetupDTCommand(TMMCCommandEnum aCommand, TMMCArgument anArgument,
   326 							TUint32 aTotalLength, TUint8* aMemoryAddress, TUint32 aBlockLength,
   327 							TBool aStopTransmission, TMMCCmdDirEnum aDir,
   328 							TUint32 aCommandClass)
   329 /**
   330  * Set up the session to issue a raw command to the card. 
   331  * This raw command function should be used when issuing a generic transfer command and argument.
   332  * Having set-up the session for this operation, the client must then engage this session before
   333  * the operation can commence.
   334  * @param aCommand
   335  * @param anArgument
   336  * @param aTotalLength
   337  * @param aMemoryAddress
   338  * @param aBlockLength
   339  * @param aStopTransmission
   340  * @param aDir
   341  * @param aCommandClass
   342  * @todo Complete the parameter descriptions
   343  */
   344 	{
   345 	OstTraceExt5( TRACE_FLOW, DMMCSESSION_SETUPDTCOMMAND_ENTRY1, "DMMCSession::SetupDTCommand;aCommand=%d;anArgument=%x;aTotalLength=%x;aMemoryAddress=%x;this=%x", (TInt) aCommand, (TUint) anArgument, (TUint) aTotalLength, (TUint) aMemoryAddress, (TUint) this );
   346 	OstTraceExt5( TRACE_FLOW, DMMCSESSION_SETUPDTCOMMAND_ENTRY2, "DMMCSession::SetupDTCommand;aBlockLength=%x;aStopTransmission=%d;aDir=%d;aCommandClass=%x;this=%x", (TUint) aBlockLength, (TInt) aStopTransmission, (TInt) aDir, (TUint) aCommandClass , (TUint) this );
   347 	ResetCommandStack();
   348 	FillCommandDesc(aCommand);
   349 	FillCommandArgs(anArgument, aTotalLength, aMemoryAddress, aBlockLength);
   350 	TMMCCommandDesc& cmd = Command();
   351 
   352 	if( aBlockLength == 0 )
   353 		cmd.iBlockLength = aTotalLength;
   354 
   355 	cmd.iSpec.iMultipleBlocks = (cmd.iBlockLength != aTotalLength);
   356 
   357 	if( aStopTransmission )
   358 		cmd.iSpec.iUseStopTransmission = ETrue;
   359 
   360 	if( aDir != EDirNone )
   361 		{
   362 		cmd.iSpec.iUseStopTransmission = aStopTransmission;
   363 		cmd.iSpec.iDirection = aDir;
   364 		}
   365 
   366 	if( aCommandClass != KMMCCmdClassNone )
   367 		cmd.iSpec.iCommandClass = aCommandClass;
   368 
   369 	iSessionID = ECIMNakedSession;
   370 	OstTraceFunctionExit1( DMMCSESSION_SETUPDTCOMMAND_EXIT, this );
   371 	}
   372 
   373 void DMMCSession::SetupCIMControl(TInt aSessID)
   374 //
   375 // find matching macro function for supplied session
   376 //
   377 	{
   378 	OstTraceFunctionEntryExt( DMMCSESSION_SETUPCIMCONTROL_ENTRY, this );
   379 	TMMCSMSTFunc f = GetMacro(aSessID);
   380 
   381 	if (f == 0)
   382 		f = DMMCStack::NoSessionSMST;
   383 
   384 	iSessionID = (TMMCSessionTypeEnum) aSessID;
   385 	iBytesTransferred = 0;
   386 	iMMCExitCode = KMMCErrNone;
   387 	iState = 0;
   388 	iInitContext = 0;
   389 	iGlobalRetries = 0;
   390 	iDoAbort = iDoStop = iDoComplete = EFalse;
   391 	iBlockOn = 0;
   392 
   393 	ResetCommandStack();
   394 
   395 	iMachine.Setup(f, iStackP);
   396 	OstTraceFunctionExit1( DMMCSESSION_SETUPCIMCONTROL_EXIT, this );
   397 	}
   398 
   399 EXPORT_C TMMCSMSTFunc DMMCSession::GetMacro(TInt aSessNum) const
   400 	{
   401 	TMMCSMSTFunc f = 0;
   402 
   403 	static const TMMCSMSTFunc macros[KMMCMaxSessionTypeNumber] =
   404 		{
   405 		DMMCStack::NakedSessionSMST,
   406 		DMMCStack::CIMUpdateAcqSMST,
   407 		DMMCStack::CIMInitStackSMST,
   408 		DMMCStack::CIMCheckStackSMST,
   409 		DMMCStack::CIMSetupCardSMST,
   410 		DMMCStack::CIMReadWriteBlocksSMST,			// CIMReadBlock
   411 		DMMCStack::CIMReadWriteBlocksSMST,			// CIMWriteBlock
   412 		DMMCStack::CIMReadWriteBlocksSMST,			// CIMReadMBlock
   413 		DMMCStack::CIMReadWriteBlocksSMST,			// CIMWriteMBlock
   414 		DMMCStack::CIMEraseSMST,
   415 		DMMCStack::CIMEraseSMST,
   416 		DMMCStack::CIMReadWriteIOSMST,
   417 		DMMCStack::CIMReadWriteIOSMST,
   418 		DMMCStack::CIMLockUnlockSMST,				// CIMLockUnlock
   419 		DMMCStack::NoSessionSMST,					// CIMLockStack is never really executed as a session
   420 		DMMCStack::InitStackAfterUnlockSMST,
   421 		DMMCStack::CIMAutoUnlockSMST,
   422 		DMMCStack::ExecSleepCommandSMST				// CIMSleep
   423 		};
   424 
   425 	if (aSessNum >= 0 && aSessNum < (TInt) KMMCMaxSessionTypeNumber)
   426 		f = macros[aSessNum];
   427 
   428 	return f;
   429 	}
   430 
   431 EXPORT_C TInt DMMCSession::Engage()
   432 /**
   433  * Enque this session for execution on the DMMCStack object which is serving it.
   434  * @return KErrBadDriver if no stack is associated with the session
   435  * @return KErrServerBusy if the stack is currently locked (and KMMCModeEnqueIfLocked flag is cleared)
   436  * @return KErrNotReady if the media is not present
   437  * @return KErrNone if successful
   438  */
   439 	{
   440 	OstTraceFunctionEntry1( DMMCSESSION_ENGAGE_ENTRY, this );
   441 	__KTRACE_OPT(KPBUS1,Kern::Printf(">ms:eng"));
   442 
   443 	if( iStackP == NULL )
   444 	    {
   445 		OstTraceFunctionExitExt( DMMCSESSION_ENGAGE_EXIT, this, KErrBadDriver );
   446 		return KErrBadDriver;
   447 	    }
   448 
   449 	if( iStackP->iLockingSessionP != NULL && iStackP->iLockingSessionP != this &&
   450 		(iStackP->EffectiveModes(iConfig) & KMMCModeEnqueIfLocked) == 0 )
   451 	    {
   452 		OstTraceFunctionExitExt( DUP1_DMMCSESSION_ENGAGE_EXIT, this, KErrServerBusy );
   453 		return KErrServerBusy;
   454 	    }
   455 
   456 	const TMediaState doorState=iStackP->MMCSocket()->iMediaChange->MediaState();
   457 
   458 	__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Eng ds = %x", doorState));
   459 	OstTrace1( TRACE_INTERNALS, DMMCSESSION_ENGAGE, "doorState = 0x%x", doorState);
   460 
   461 	if (doorState == EDoorOpen)
   462 	    {
   463 		OstTraceFunctionExitExt( DUP2_DMMCSESSION_ENGAGE_EXIT, this, KErrNotReady );
   464 		return KErrNotReady;
   465 	    }
   466 
   467 	SetupCIMControl(iSessionID);
   468 
   469 	iStackP->Add(this);
   470 
   471 	__KTRACE_OPT(KPBUS1,Kern::Printf("<ms:eng"));
   472 	OstTraceFunctionExitExt( DUP3_DMMCSESSION_ENGAGE_EXIT, this, KErrNone );
   473 	return KErrNone;
   474 	}
   475 
   476 // Command specification table for standard MMC commands (CMD0 - CMD63)
   477 extern const TMMCCommandSpec CommandTable[KMMCCommandMask+1] =
   478 	{//  Class				  Type			Dir			MBlk	StopT	Rsp Type		  Len	Cmd No
   479 	{KMMCCmdClassBasic,		ECmdTypeBC,		EDirNone,	EFalse, EFalse, ERespTypeNone,		0}, //CMD0
   480 	{KMMCCmdClassBasic,		ECmdTypeBCR,	EDirNone,	EFalse, EFalse, ERespTypeR3,		4}, //CMD1
   481 	{KMMCCmdClassBasic,		ECmdTypeBCR,	EDirNone,	EFalse, EFalse, ERespTypeR2,		16},//CMD2
   482 	{KMMCCmdClassBasic,		ECmdTypeAC,		EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD3
   483 	{KMMCCmdClassBasic,		ECmdTypeBC,		EDirNone,	EFalse, EFalse, ERespTypeNone,		0}, //CMD4
   484 	{KMMCCmdClassBasic,		ECmdTypeAC,		EDirNone,	EFalse, EFalse, ERespTypeR1B,		0}, //CMD5 - SLEEP/AWAKE
   485 	{KMMCCmdClassBasic,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1B,		0}, //CMD6
   486 	{KMMCCmdClassBasic,		ECmdTypeAC,		EDirNone,	EFalse, EFalse, ERespTypeR1B,		4}, //CMD7
   487 	{KMMCCmdClassBasic,		ECmdTypeADTCS,	EDirRead,	EFalse, EFalse, ERespTypeR1,		512}, //CMD8
   488 	{KMMCCmdClassBasic,		ECmdTypeAC,		EDirNone,	EFalse, EFalse, ERespTypeR2,		16},//CMD9
   489 	{KMMCCmdClassBasic,		ECmdTypeAC,		EDirNone,	EFalse, EFalse, ERespTypeR2,		16},//CMD10
   490 	{KMMCCmdClassStreamRead,ECmdTypeADTCS,	EDirRead,	EFalse, ETrue,	ERespTypeR1,		4}, //CMD11
   491 	{KMMCCmdClassBasic,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1B,		4}, //CMD12
   492 	{KMMCCmdClassBasic,		ECmdTypeAC,		EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD13
   493 	{KMMCCmdClassBlockRead,	ECmdTypeADTCS,	EDirRead,	EFalse, EFalse, ERespTypeR1,		4}, //CMD14 - BUSTEST_R
   494 	{KMMCCmdClassBasic,		ECmdTypeAC,		EDirNone,	EFalse, EFalse, ERespTypeNone,		0}, //CMD15
   495 	{KMMCCmdClassBlockRead,	ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD16
   496 	{KMMCCmdClassBlockRead,	ECmdTypeADTCS,	EDirRead,	EFalse, EFalse, ERespTypeR1,		4}, //CMD17
   497 	{KMMCCmdClassBlockRead,	ECmdTypeADTCS,	EDirRead,	ETrue,	ETrue,	ERespTypeR1,		4}, //CMD18
   498 	{KMMCCmdClassBlockWrite,ECmdTypeADTCS,	EDirWrite,	EFalse, EFalse, ERespTypeR1,		4}, //CMD19 - BUSTEST_W
   499 	{KMMCCmdClassStreamWrite,ECmdTypeADTCS, EDirWrite,	EFalse, ETrue,	ERespTypeR1,		4}, //CMD20
   500 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD21
   501 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD22
   502 	{KMMCCmdClassBlockRead | 
   503 	 KMMCCmdClassBlockWrite,ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1,	4}, //CMD23
   504 	{KMMCCmdClassBlockWrite,ECmdTypeADTCS,	EDirWrite,	EFalse, EFalse, ERespTypeR1,		4}, //CMD24
   505 	{KMMCCmdClassBlockWrite,ECmdTypeADTCS,	EDirWrite,	ETrue,	ETrue,	ERespTypeR1,		4}, //CMD25
   506 	{KMMCCmdClassBlockWrite,ECmdTypeADTCS,	EDirWrite,	EFalse, EFalse, ERespTypeR1,		4}, //CMD26
   507 	{KMMCCmdClassBlockWrite,ECmdTypeADTCS,	EDirWrite,	EFalse, EFalse, ERespTypeR1,		4}, //CMD27
   508 	{KMMCCmdClassWriteProtection,ECmdTypeACS,EDirNone,	EFalse, EFalse, ERespTypeR1B,		4}, //CMD28
   509 	{KMMCCmdClassWriteProtection,ECmdTypeACS,EDirNone,	EFalse, EFalse, ERespTypeR1B,		4}, //CMD29
   510 	{KMMCCmdClassWriteProtection,ECmdTypeADTCS,EDirRead,EFalse, EFalse, ERespTypeR1,		4}, //CMD30
   511 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD31
   512 	{KMMCCmdClassErase,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD32
   513 	{KMMCCmdClassErase,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD33
   514 	{KMMCCmdClassErase,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD34
   515 	{KMMCCmdClassErase,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD35
   516 	{KMMCCmdClassErase,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD36
   517 	{KMMCCmdClassErase,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD37
   518 	{KMMCCmdClassErase,		ECmdTypeACS,	EDirNone,	EFalse, EFalse, ERespTypeR1B,		4}, //CMD38
   519 	{KMMCCmdClassIOMode,	ECmdTypeAC,		EDirNone,	EFalse, EFalse, ERespTypeR4,		4}, //CMD39
   520 	{KMMCCmdClassIOMode,	ECmdTypeBCR,	EDirNone,	EFalse, EFalse, ERespTypeR5,		4}, //CMD40
   521 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD41
   522 	{KMMCCmdClassLockCard,	ECmdTypeADTCS,	EDirWrite,	EFalse, EFalse, ERespTypeR1B,		4}, //CMD42
   523 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD43
   524 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD44
   525 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD45
   526 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD46
   527 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD47
   528 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD48
   529 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD49
   530 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD50
   531 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD51
   532 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD52
   533 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD53
   534 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD54
   535 	{KMMCCmdClassApplication,ECmdTypeAC,	EDirNone,	EFalse, EFalse, ERespTypeR1,		4}, //CMD55
   536 	{KMMCCmdClassApplication,ECmdTypeADTCS,	EDirRBit0,	EFalse, EFalse, ERespTypeR1B,		4}, //CMD56
   537 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD57
   538 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD58
   539 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD59
   540 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD60
   541 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD61
   542 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}, //CMD62
   543 	{KMMCCmdClassNone,		ECmdTypeUK,		EDirNone,	EFalse, EFalse, ERespTypeUnknown,	0}	//CMD63
   544 	};
   545 
   546 
   547 EXPORT_C void DMMCSession::FillCommandDesc()
   548 /**
   549  * Fills the current command descriptor with the default data according to MMC spec V2.1
   550  */
   551 	{
   552 	OstTraceFunctionEntry1( DMMCSESSION_FILLCOMMANDDESC1_ENTRY, this );
   553 	TMMCCommandDesc& cmd = Command();
   554 	cmd.iSpec = CommandTable[cmd.iCommand & KMMCCommandMask];
   555 
   556 	cmd.iFlags = 0;
   557 	cmd.iBytesDone = 0;
   558 	OstTraceFunctionExit1( DMMCSESSION_FILLCOMMANDDESC1_EXIT, this );
   559 	}
   560 
   561 EXPORT_C void DMMCSession::FillCommandDesc(TMMCCommandEnum aCommand)
   562 /**
   563  * Initialises the current command according to whether it is a normal
   564  * or an application command.
   565  * @param aCommand Contains the command.
   566  */
   567 	{
   568 	OstTraceExt2(TRACE_FLOW, DMMCSESSION_FILLCOMMANDDESC2_ENTRY, "DMMCSession::FillCommandDesc;aCommand=%d;this=%x", (TInt) aCommand, (TUint) this);
   569 	Command().iCommand = aCommand;
   570 	Command().iArgument = 0;					// set stuff bits to zero
   571 	FillCommandDesc();
   572 	OstTraceFunctionExit1( DMMCSESSION_FILLCOMMANDDESC2_EXIT, this );
   573 	}
   574 
   575 EXPORT_C void DMMCSession::FillCommandDesc(TMMCCommandEnum aCommand, TMMCArgument anArgument)
   576 /**
   577  * Initialises the current command with an argument according to whether
   578  * it is a normal or an application command.
   579  * @param aCommand Contains the command.
   580  * @param anArgument Specifies the argument.
   581  */
   582 	{
   583 	OstTraceExt3(TRACE_FLOW, DMMCSESSION_FILLCOMMANDDESC3_ENTRY, "DMMCSession::FillCommandDesc;aCommand=%d;anArgument=%x;this=%x", (TInt) aCommand, (TUint) anArgument, (TUint) this);
   584 	TMMCCommandDesc& cmd = Command();
   585 	cmd.iCommand = aCommand;
   586 	FillCommandDesc();
   587 	cmd.iArgument = anArgument;
   588 	OstTraceFunctionExit1( DMMCSESSION_FILLCOMMANDDESC3_EXIT, this );
   589 	}
   590 
   591 EXPORT_C void DMMCSession::FillCommandArgs(TMMCArgument anArgument, TUint32 aLength, TUint8* aMemoryP,
   592 								  TUint32 aBlkLen)
   593 /**
   594  * Initialises the current commands arguments with the specified parameters
   595  * It is necessary to have set the command arguments with this command prior
   596  * to engaging a read/write macro or command.
   597  * @param anArgument Command specific argument.
   598  * @param aLength aLength Total number of bytes to read/write.
   599  * @param aMemoryP Host source/destination address
   600  * @param aBlkLen Block length
   601  */
   602 	{
   603 	OstTraceExt5(TRACE_FLOW, DMMCSESSION_FILLCOMMANDARGS_ENTRY ,"DMMCSession::FillCommandArgs;anArgument=%x;aLength=%x;aMemoryP=%x;aBlkLen=%x;this=%x", (TUint) anArgument, (TUint) aLength, (TUint) aMemoryP, (TUint) aBlkLen, (TUint) this);
   604 	TMMCCommandDesc& cmd = Command();
   605 
   606 	cmd.iArgument = anArgument;
   607 	cmd.iTotalLength = aLength;
   608 	cmd.iDataMemoryP = aMemoryP;
   609 	cmd.iBlockLength = aBlkLen;
   610 	cmd.iFlags = 0;
   611 	OstTraceFunctionExit1( DMMCSESSION_FILLCOMMANDARGS_EXIT, this );
   612 	}
   613 
   614 const TMMCCommandSpec& DMMCSession::FindCommandSpec(const TMMCIdxCommandSpec aSpecs[], TInt aIdx)
   615 /**
   616  * Searches the supplied command specification list for the specification corresponding to the
   617  * supplied command.
   618  * @param aSpecs The command specification list to be searched.
   619  * @param aIdx The requested command.
   620  */
   621 	{
   622 	OstTraceFunctionEntry0( DMMCSESSION_FINDCOMMANDSPEC_ENTRY );	
   623 	TInt i = 0;
   624 	while (aSpecs[i].iIdx != aIdx)
   625 		++i;
   626 	OstTraceFunctionExit0( DMMCSESSION_FINDCOMMANDSPEC_EXIT );
   627 	return aSpecs[i].iSpec;
   628 	}
   629 
   630 void DMMCSession::SynchBlock(TUint32 aFlag)
   631 //
   632 // Blocks a session synchronously (within scheduler context)
   633 //
   634 	{
   635 	OstTraceFunctionEntryExt( DMMCSESSION_SYNCHBLOCK_ENTRY, this );
   636 	(void)__e32_atomic_ior_ord32(&iBlockOn, aFlag);
   637 	OstTraceFunctionExit1( DMMCSESSION_SYNCHBLOCK_EXIT, this );
   638 	}
   639 
   640 void DMMCSession::SynchUnBlock(TUint32 aFlag)
   641 //
   642 // Unblocks a session synchronously (within scheduler context)
   643 //
   644 	{
   645 	OstTraceFunctionEntryExt( DMMCSESSION_SYNCHUNBLOCK_ENTRY, this );
   646 	if( (iBlockOn & aFlag) == 0 )
   647 	    {
   648 		OstTraceFunctionExit1( DMMCSESSION_SYNCHUNBLOCK_EXIT, this );
   649 		return;
   650 	    }
   651 
   652 	(void)__e32_atomic_and_ord32(&iBlockOn, ~aFlag);
   653 	OstTraceFunctionExit1( DUP1_DMMCSESSION_SYNCHUNBLOCK_EXIT, this );
   654 	}
   655 
   656 EXPORT_C TRCA DMMCSession::CardRCA()
   657 /**
   658  * Checks that the card is still the same and ready
   659  * @return A TRCA object containing the card's RCA (or 0 if the card is not ready)
   660  */
   661 	{
   662 
   663 	// Rely on 'CardIsGone' bit rather than a CID comparison	
   664 	if ( iCardP != NULL && iCardP->IsPresent() && !(iState & KMMCSessStateCardIsGone) ) 
   665 		return( iCardP->RCA() );
   666 	return(0);
   667 	}
   668 
   669 #ifdef __EPOC32__
   670 void DMMCSession::ProgramTimerCallBack(TAny* aSessP)
   671 	{
   672 	OstTraceFunctionEntry0( DMMCSESSION_PROGRAMTIMERCALLBACK_ENTRY );
   673 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mss:pgtcb"));
   674 	
   675     static_cast<DMMCSession *>(aSessP)->iState |= KMMCSessStateDoDFC;
   676 	static_cast<DMMCSession *>(aSessP)->UnBlock(KMMCBlockOnPgmTimer, KMMCErrNone);
   677 	OstTraceFunctionExit0( DMMCSESSION_PROGRAMTIMERCALLBACK_EXIT );
   678 	}
   679 
   680 void DMMCSession::PollTimerCallBack(TAny* aSessP)
   681 	{
   682 	OstTraceFunctionEntry0( DMMCSESSION_POLLTIMERCALLBACK_ENTRY );
   683 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mss:ptcb"));
   684 
   685     static_cast<DMMCSession *>(aSessP)->iState |= KMMCSessStateDoDFC;
   686 	static_cast<DMMCSession *>(aSessP)->UnBlock(KMMCBlockOnPollTimer, KMMCErrNone);
   687 	OstTraceFunctionExit0( DMMCSESSION_POLLTIMERCALLBACK_EXIT );
   688 	}
   689 
   690 void DMMCSession::RetryTimerCallBack(TAny* aSessP)
   691 	{
   692 	OstTraceFunctionEntry0( DMMCSESSION_RETRYTIMERCALLBACK_ENTRY );
   693 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mss:rtcb"));
   694 
   695     static_cast<DMMCSession *>(aSessP)->iState |= KMMCSessStateDoDFC;
   696 	static_cast<DMMCSession *>(aSessP)->UnBlock(KMMCBlockOnRetryTimer, KMMCErrNone);
   697 	OstTraceFunctionExit0( DMMCSESSION_RETRYTIMERCALLBACK_EXIT );
   698 	}
   699 
   700 #endif	// #ifdef __EPOC32__
   701 
   702 EXPORT_C TInt DMMCSession::EpocErrorCode() const
   703 /**
   704  * Returns the last Symbian OS style error code returned in this session. 
   705  * The Symbian OS error code is derived from both the last MMC specific exit code MMCExitCode()
   706  * and the last status information from the card (iLastStatus).
   707  * @return Standard Symbian OS error code
   708  */
   709 	{
   710 	OstTraceFunctionEntry1( DMMCSESSION_EPOCERRORCODE_ENTRY, this );
   711 	__KTRACE_OPT(KPBUS1,Kern::Printf("=mss:eee:%08x,%08x", MMCExitCode(), LastStatus().State() ));
   712 	OstTraceExt2( TRACE_INTERNALS, DMMCSESSION_EPOCERRORCODE, "MMCExitCode = 0x%08x; LastStatus State = 0x%08x", (TUint) MMCExitCode(), (TUint) LastStatus().State());
   713 	
   714 	struct errorTableEntry
   715 		{
   716 		TUint32 iMask;
   717 		TInt iErrorCode;
   718 		};
   719 
   720 	static const errorTableEntry mmcTable[] = 
   721 		{
   722 		{KMMCErrNotSupported,									KErrNotSupported},
   723 		{KMMCErrStackNotReady,									KErrBadPower},
   724 		{KMMCErrArgument,										KErrArgument},
   725 		{KMMCErrBrokenLock | KMMCErrPowerDown | KMMCErrAbort,	KErrAbort},
   726 		{KMMCErrNoCard | KMMCErrResponseTimeOut | KMMCErrDataTimeOut |
   727 			KMMCErrBusyTimeOut | KMMCErrBusTimeOut,				KErrNotReady},
   728 		{KMMCErrResponseCRC|KMMCErrDataCRC|KMMCErrCommandCRC,	KErrCorrupt},
   729 		{KMMCErrLocked,											KErrLocked},
   730 		{KMMCErrNotFound,										KErrNotFound},
   731 		{KMMCErrAlreadyExists,									KErrAlreadyExists},
   732 		{KMMCErrGeneral,										KErrGeneral},
   733 		{~0UL,													KErrUnknown}
   734 		};
   735 
   736 	static const errorTableEntry statusTable[] = 
   737 		{
   738 		{KMMCStatErrOverrun|KMMCStatErrUnderrun|
   739 			KMMCStatErrCardECCFailed|KMMCStatErrComCRCError,	KErrGeneral},
   740 		{KMMCStatErrCSDOverwrite|KMMCStatErrWPViolation,		KErrWrite},
   741 		{KMMCStatErrLockUnlock,									KErrLocked},
   742 		{KMMCStatErrIllegalCommand,								KErrNotSupported},
   743 		{KMMCStatErrEraseParam|KMMCStatErrEraseSeqError|
   744 			KMMCStatErrBlockLenError|KMMCStatErrAddressError|
   745 			KMMCStatErrOutOfRange,								KErrArgument},
   746 		{~0UL,													KErrUnknown}
   747 		};
   748 
   749 	TUint32 errCode = MMCExitCode();
   750 
   751 	if( errCode == 0 )
   752 	    {
   753 		OstTraceFunctionExitExt( DMMCSESSION_EPOCERRORCODE_EXIT, this, KErrNone );
   754 		return KErrNone;
   755 	    }
   756 
   757 	const errorTableEntry* ptr = &mmcTable[0];
   758 
   759 	if( errCode == KMMCErrStatus )
   760 		{
   761 		ptr = &statusTable[0];
   762 
   763 		if( (errCode = LastStatus()) == 0 )
   764 		    {
   765 			OstTraceFunctionExitExt( DUP1_DMMCSESSION_EPOCERRORCODE_EXIT, this, KErrUnknown );
   766 			return KErrUnknown;
   767 		    }
   768 		}
   769 
   770 	for( ;; )
   771 		if( (errCode & ptr->iMask) != 0 )
   772 		    {
   773 		    TInt ret = ptr->iErrorCode; 
   774 			OstTraceFunctionExitExt( DUP2_DMMCSESSION_EPOCERRORCODE_EXIT, this, ret );
   775 			return ret;
   776 		    }
   777 		else
   778 			ptr++;
   779 	}