Convert Kernelhwsrv package from SFL to EPL
kernel\eka\compsupp is subject to the ARM EABI LICENSE
userlibandfileserver\fatfilenameconversionplugins\unicodeTables is subject to the Unicode license
kernel\eka\kernel\zlib is subject to the zlib license
// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//
#include <drivers/mmc.h>
// -------- class DMMCSession --------
EXPORT_C DMMCSession::DMMCSession(const TMMCCallBack& aCallBack)
/**
* Constructor - initializes callbacks and timers.
* Once the session has been engaged, the completion of the request is signalled by calling
* the function provided in aCallback. A session will be completed in this way if it has completed
* normally, an error has occurred or the session has been stopped by this or another client.
* @param aCallBack reference to a TMMCCallback object to be called upon completion.
*/
: iCallBack(aCallBack),
#ifdef __EPOC32__
iPollTimer(DMMCSession::PollTimerCallBack, this),
iRetryTimer(DMMCSession::RetryTimerCallBack, this),
iProgramTimer(DMMCSession::ProgramTimerCallBack, this),
#endif // #ifdef __EPOC32__
iConfig()
{
}
EXPORT_C DMMCSession::~DMMCSession()
/**
* Destructor.
*/
{
// Ensure that the stack isn't currently running in another thread's context, otherwise this session won't be
// removed from the stack's workset until some time later - by which time the session will have been deleted
__ASSERT_ALWAYS(!iStackP->StackRunning(), DMMCSocket::Panic(DMMCSocket::EMMCNotInDfcContext));
Abort();
UnlockStack();
}
EXPORT_C void DMMCSession::SetCard(TMMCard* aCardP)
/**
* Assigns a card to the session. The card pointer would normally be obtained via a call of DMMCStack::CardP().
* Assigning a card to the session is the means by which a particular card in the stack is targeted for a
* particular request. Some requests involve broadcasting to the entire stack. However, the majority involve
* an individual card at some stage of the process and so an attempt to engage the session before a card has
* been assigned to it will generally fail straight away. It is possible to change the card assigned to the
* session as long as this is not attempted while the session is engaged.
* @param aCardP A pointer to the card to be assigned to the session.
*/
{
iCardP = aCardP;
iCID = iCardP->CID();
}
EXPORT_C void DMMCSession::SetupCIMReadBlock(TMMCArgument aDevAddr, TUint32 aLength, TUint8* aMemoryP)
/**
* Sets the session up to perform the CIM_READ_BLOCK macro as outlined by the MMCA.
* Having set-up the session for this operation, the client must then engage the session before the operation can commence.
* The CIM_READ_BLOCK macro reads a single block from the card. It starts by setting the block length (CMD16) as specified
* in 'aLength'. It then reads a single block of data (CMD17) from the card at offset 'aDevAddr' on the card into system
* memory starting at address 'aMemoryP'.
* @param aDevAddr Contains offset to the block to be read from the card
* @param aLength Block length
* @param aMemoryP host destination address
*/
{
ResetCommandStack();
FillCommandArgs(aDevAddr, aLength, aMemoryP, aLength);
iSessionID = ECIMReadBlock;
}
EXPORT_C void DMMCSession::SetupCIMWriteBlock(TMMCArgument aDevAddr, TUint32 aLength, TUint8* aMemoryP)
/**
* Set up the session to perform the CIM_WRITE_BLOCK macro as outlined by the MMCA.
* Having set-up the session for this operation, the client must then engage the session before the operation can commence.
* The CIM_WRITE_BLOCK macro writes a single block to the card. It starts by setting the block length (CMD16) as specified
* in 'aLength'. It then writes a single block of data (CMD24) to the card at offset 'aDevAddr' on the card reading from system
* memory starting at address 'aMemoryP'.
* @param aDevAddr Contains offset to the block to be written on the card
* @param aLength Block length
* @param aMemoryP Host source address
*/
{
ResetCommandStack();
FillCommandArgs(aDevAddr, aLength, aMemoryP, aLength);
iSessionID = ECIMWriteBlock;
}
EXPORT_C void DMMCSession::SetupCIMReadMBlock(TMMCArgument aDevAddr, TUint32 aLength, TUint8* aMemoryP, TUint32 aBlkLen)
/**
* Set up the session to perform the CIM_READ_MBLOCK macro as outlined by the MMCA.
* Having set-up the session for this operation, the client must then engage the session before the operation can commence.
* The CIM_READ_MBLOCK macro reads a series of blocks from the card. It starts by setting the block length (CMD16) as specified
* in 'aBlkLen'. It then issues the read multiple block command (CMD18) to continually transfer blocks from the card to host
* starting at offset 'aDevAddr' on the card into system memory starting at address 'aMemoryP'. This continues until 'aLength'
* bytes have been read at which point the Controller issues the stop command (CMD12) to halt the transfer.
* @param aDevAddr Contains offset to the block to be read from the card
* @param aLength Total number of bytes to read.
* @param aMemoryP Host destination address
* @param aBlkLen Block length
*/
{
ResetCommandStack();
FillCommandArgs(aDevAddr, aLength, aMemoryP, aBlkLen);
iSessionID = ECIMReadMBlock;
}
EXPORT_C void DMMCSession::SetupCIMWriteMBlock(TMMCArgument aDevAddr, TUint32 aLength, TUint8* aMemoryP, TUint32 aBlkLen)
/**
* Set up the session to perform the CIM_WRITE_MBLOCK macro as outlined by the MMCA.
* Having set-up the session for this operation, the client must then engage the session before the operation can commence.
* The CIM_WRITE_MBLOCK macro writes a series of blocks to the card. It starts by setting the block length (CMD16) as specified
* in 'aBlkLen'. It then issues the write multiple block command (CMD25) to continually transfer blocks from host to the card
* starting at address 'aMemoryP' in system memory and offset 'aDevAddr' on the card.. This continues until 'aLength' bytes have
* been written at which point the Controller issues the stop command (CMD12) to halt the transfer
* @param aDevAddr Contains offset to the block to be written on the card
* @param aLength Total number of bytes to write.
* @param aMemoryP Host source address
* @param aBlkLen Block length
*/
{
ResetCommandStack();
FillCommandArgs(aDevAddr, aLength, aMemoryP, aBlkLen);
iSessionID = ECIMWriteMBlock;
}
EXPORT_C void DMMCSession::SetupCIMEraseSector(TMMCArgument aDevAddr, TUint32 aLength)
/**
* Set up the session to perform the CIM_ERASE_SECTOR macro broadly as outlined by the MMCA.
* However, the macro only performs a sector erase of a contiguous area and doesn't support the un-tagging of particular sectors
* within the initial tagged area. Having set-up the session for this operation, the client must then engage the session before
* the operation can commence.
* The CIM_ERASE_SECTOR macro erases a range of sectors on the card starting at offset 'aDevAddr' on the card and ending at offset
* 'aDevAdd'+'aLength'. The entire area specified must lie within a single erase group. (The erase group size can be read from the CSD).
* The specified start offset and end offset need not coincide exactly with a sector boundary since the card will ignore LSBs below
* the sector size. The tag sector start command (CMD32) is first issued setting the address of the first sector to be erased.
* This is followed by the tag sector end command (CMD33) setting the address of the last sector to be erased. Now that the erase
* sectors are tagged, the erase command (CMD38) is sent followed by a send status command (CMD13) to read any additional status
* information from the card.
* @param aDevAddr Contains offset to the first block to be erased
* @param aLength Total number of bytes to erase
*/
{
ResetCommandStack();
FillCommandArgs(aDevAddr, aLength, NULL, 0);
iSessionID = ECIMEraseSector;
}
EXPORT_C void DMMCSession::SetupCIMEraseGroup(TMMCArgument aDevAddr, TUint32 aLength)
/**
* Set up the session to perform the CIM_ERASE_GROUP macro broadly as outlined by the MMCA.
* However, the macro only performs an erase group erase of a contiguous area and doesn't support the un-tagging of particular
* erase groups within the initial tagged area. Having set-up the session for this operation, the client must then engage the
* session before the operation can commence.
* The CIM_ERASE_GROUP macro erases a range of erase groups on the card starting at offset 'aDevAddr' on the card and ending at
* offset 'aDevAdd'+'aLength'. The specified start offset and end offset need not coincide exactly with an erase group boundary
* since the card will ignore LSBs below the erase group size. The tag ease group start command (CMD35) is first issued setting
* the address of the first erase group to be erased. This is followed by the tag erase group end command (CMD36) setting the
* address of the last erase group to be erased. Now that the erase groups are tagged, the erase command (CMD38) is sent followed
* by a send status command (CMD13) to read any additional status information from the card.
* @param aDevAddr Contains offset to the first block to be erased
* @param aLength Total number of bytes to erase
*/
{
ResetCommandStack();
FillCommandArgs(aDevAddr, aLength, NULL, 0);
iSessionID = ECIMEraseGroup;
}
EXPORT_C void DMMCSession::SetupCIMReadIO(TUint8 aRegAddr, TUint32 aLength, TUint8* aMemoryP)
/**
* Set up the session to perform the read i/o macro (CMD39).
* 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,
* reading 'aLength' bytes of data from I/O register 'aRegAddr' on the card into system memory starting at address 'aMemoryP'.
* Having set-up the session for this operation, the client must then engage the session before the operation can commence.
* @param aRegAddr Address of IO register
* @param aLength Total number of bytes to read
* @param aMemoryP Host destination address
*/
{
ResetCommandStack();
FillCommandArgs(aRegAddr, aLength, aMemoryP, 0);
iSessionID = ECIMReadIO;
}
EXPORT_C void DMMCSession::SetupCIMWriteIO(TUint8 aRegAddr, TUint32 aLength, TUint8* aMemoryP)
/**
* Set up the session to perform the write i/o macro (CMD39).
* 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,
* writing 'aLength' bytes of data to I/O register 'aRegAddr' on the card from system memory starting at address 'aMemoryP'.
* Having set-up the session for this operation, the client must then engage the session before the operation can commence.
* @param aRegAddr Address of IO register
* @param aLength Total number of bytes to write
* @param aMemoryP Host source address
*/
{
ResetCommandStack();
FillCommandArgs(aRegAddr, aLength, aMemoryP, 0);
iSessionID = ECIMWriteIO;
}
EXPORT_C void DMMCSession::SetupCIMLockUnlock(TUint32 aLength, TUint8* aMemoryP)
/**
* Set up the session to perform the lock-unlock macro (CMD42).
* This macro is used to manage the password protection feature (if supported) on a MultiMediaCard.
* This same macro is used to lock or unlock a card, set or clear a password or force erase a card.
* Having set-up the session for the required operation, the client must then engage the session before
* the operation can commence.
* The block length (CMD16) as specified in 'aLength' is first set. The lock unlock command (CMD42) is
* then issued. This command has the same structure as a regular single block write command.
* A data block is written to the card from system memory starting at address 'aMemoryP'. The transferred
* data block should contain the password setting mode, the password length and the password data if appropriate.
* @param aLength Block length
* @param aMemoryP Host source address containing password data
*/
{
__KTRACE_OPT(KPBUS1, Kern::Printf("ms:slu%08x", aLength));
ResetCommandStack();
FillCommandDesc(ECmdLockUnlock);
FillCommandArgs(0, aLength, aMemoryP, aLength);
iSessionID = ECIMLockUnlock;
}
EXPORT_C void DMMCSession::SetupCommand(TMMCCommandEnum aCommand, TMMCArgument anArgument)
/**
* Set up the session to issue a raw command to the card.
* This raw command function should be used when issuing a known command with or without an argument.
* Having set-up the session for this operation, the client must then engage this session before
* the operation can commence.
* @param aCommand Command to be sent
* @param anArgument Associated argument
*/
{
ResetCommandStack();
FillCommandDesc(aCommand, anArgument);
iSessionID = ECIMNakedSession;
}
EXPORT_C void DMMCSession::SetupRSCommand(TMMCCommandEnum aCommand, TMMCArgument anArgument,
TUint32 aResponseLength, TMMCCommandTypeEnum aCommandType,
TMMCResponseTypeEnum aResponseType,
TUint32 aCommandClass)
/**
* Set up the session to issue a raw command to the card.
* This raw command function should be used when issuing an unknown command, an argument and an unknown response type.
* Having set-up the session for this operation, the client must then engage this session before the operation can commence.
* @param aCommand
* @param anArgument
* @param aResponseLength
* @param aCommandType
* @param aResponseType
* @param aCommandClass
* @todo Complete the parameter descriptions
*/
{
ResetCommandStack();
FillCommandDesc(aCommand, anArgument);
TMMCCommandSpec& cmdSpec = Command().iSpec;
cmdSpec.iDirection = EDirNone;
if( aResponseLength <= KMMCMaxResponseLength )
cmdSpec.iResponseLength = aResponseLength;
if( aCommandType != ECmdTypeUK )
cmdSpec.iCommandType = aCommandType;
if( aResponseType != ERespTypeUnknown )
cmdSpec.iResponseType = aResponseType;
if( aCommandClass != KMMCCmdClassNone )
cmdSpec.iCommandClass = aCommandClass;
iSessionID = ECIMNakedSession;
}
EXPORT_C void DMMCSession::SetupDTCommand(TMMCCommandEnum aCommand, TMMCArgument anArgument,
TUint32 aTotalLength, TUint8* aMemoryAddress, TUint32 aBlockLength,
TBool aStopTransmission, TMMCCmdDirEnum aDir,
TUint32 aCommandClass)
/**
* Set up the session to issue a raw command to the card.
* This raw command function should be used when issuing a generic transfer command and argument.
* Having set-up the session for this operation, the client must then engage this session before
* the operation can commence.
* @param aCommand
* @param anArgument
* @param aTotalLength
* @param aMemoryAddress
* @param aBlockLength
* @param aStopTransmission
* @param aDir
* @param aCommandClass
* @todo Complete the parameter descriptions
*/
{
ResetCommandStack();
FillCommandDesc(aCommand);
FillCommandArgs(anArgument, aTotalLength, aMemoryAddress, aBlockLength);
TMMCCommandDesc& cmd = Command();
if( aBlockLength == 0 )
cmd.iBlockLength = aTotalLength;
cmd.iSpec.iMultipleBlocks = (cmd.iBlockLength != aTotalLength);
if( aStopTransmission )
cmd.iSpec.iUseStopTransmission = ETrue;
if( aDir != EDirNone )
{
cmd.iSpec.iUseStopTransmission = aStopTransmission;
cmd.iSpec.iDirection = aDir;
}
if( aCommandClass != KMMCCmdClassNone )
cmd.iSpec.iCommandClass = aCommandClass;
iSessionID = ECIMNakedSession;
}
void DMMCSession::SetupCIMControl(TInt aSessID)
//
// find matching macro function for supplied session
//
{
TMMCSMSTFunc f = GetMacro(aSessID);
if (f == 0)
f = DMMCStack::NoSessionSMST;
iSessionID = (TMMCSessionTypeEnum) aSessID;
iBytesTransferred = 0;
iMMCExitCode = KMMCErrNone;
iState = 0;
iInitContext = 0;
iGlobalRetries = 0;
iDoAbort = iDoStop = iDoComplete = EFalse;
iBlockOn = 0;
ResetCommandStack();
iMachine.Setup(f, iStackP);
}
EXPORT_C TMMCSMSTFunc DMMCSession::GetMacro(TInt aSessNum) const
{
TMMCSMSTFunc f = 0;
static const TMMCSMSTFunc macros[KMMCMaxSessionTypeNumber] =
{
DMMCStack::NakedSessionSMST,
DMMCStack::CIMUpdateAcqSMST,
DMMCStack::CIMInitStackSMST,
DMMCStack::CIMCheckStackSMST,
DMMCStack::CIMSetupCardSMST,
DMMCStack::CIMReadWriteBlocksSMST, // CIMReadBlock
DMMCStack::CIMReadWriteBlocksSMST, // CIMWriteBlock
DMMCStack::CIMReadWriteBlocksSMST, // CIMReadMBlock
DMMCStack::CIMReadWriteBlocksSMST, // CIMWriteMBlock
DMMCStack::CIMEraseSMST,
DMMCStack::CIMEraseSMST,
DMMCStack::CIMReadWriteIOSMST,
DMMCStack::CIMReadWriteIOSMST,
DMMCStack::CIMLockUnlockSMST, // CIMLockUnlock
DMMCStack::NoSessionSMST, // CIMLockStack is never really executed as a session
DMMCStack::InitStackAfterUnlockSMST,
DMMCStack::CIMAutoUnlockSMST,
DMMCStack::ExecSleepCommandSMST // CIMSleep
};
if (aSessNum >= 0 && aSessNum < (TInt) KMMCMaxSessionTypeNumber)
f = macros[aSessNum];
return f;
}
EXPORT_C TInt DMMCSession::Engage()
/**
* Enque this session for execution on the DMMCStack object which is serving it.
* @return KErrBadDriver if no stack is associated with the session
* @return KErrServerBusy if the stack is currently locked (and KMMCModeEnqueIfLocked flag is cleared)
* @return KErrNotReady if the media is not present
* @return KErrNone if successful
*/
{
__KTRACE_OPT(KPBUS1,Kern::Printf(">ms:eng"));
if( iStackP == NULL )
return( KErrBadDriver );
if( iStackP->iLockingSessionP != NULL && iStackP->iLockingSessionP != this &&
(iStackP->EffectiveModes(iConfig) & KMMCModeEnqueIfLocked) == 0 )
return( KErrServerBusy );
const TMediaState doorState=iStackP->MMCSocket()->iMediaChange->MediaState();
__KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Eng ds = %x", doorState));
if (doorState == EDoorOpen)
return KErrNotReady;
SetupCIMControl(iSessionID);
iStackP->Add(this);
__KTRACE_OPT(KPBUS1,Kern::Printf("<ms:eng"));
return(KErrNone);
}
// Command specification table for standard MMC commands (CMD0 - CMD63)
extern const TMMCCommandSpec CommandTable[KMMCCommandMask+1] =
{// Class Type Dir MBlk StopT Rsp Type Len Cmd No
{KMMCCmdClassBasic, ECmdTypeBC, EDirNone, EFalse, EFalse, ERespTypeNone, 0}, //CMD0
{KMMCCmdClassBasic, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR3, 4}, //CMD1
{KMMCCmdClassBasic, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR2, 16},//CMD2
{KMMCCmdClassBasic, ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD3
{KMMCCmdClassBasic, ECmdTypeBC, EDirNone, EFalse, EFalse, ERespTypeNone, 0}, //CMD4
{KMMCCmdClassBasic, ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR1B, 0}, //CMD5 - SLEEP/AWAKE
{KMMCCmdClassBasic, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1B, 0}, //CMD6
{KMMCCmdClassBasic, ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR1B, 4}, //CMD7
{KMMCCmdClassBasic, ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 512}, //CMD8
{KMMCCmdClassBasic, ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR2, 16},//CMD9
{KMMCCmdClassBasic, ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR2, 16},//CMD10
{KMMCCmdClassStreamRead,ECmdTypeADTCS, EDirRead, EFalse, ETrue, ERespTypeR1, 4}, //CMD11
{KMMCCmdClassBasic, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1B, 4}, //CMD12
{KMMCCmdClassBasic, ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD13
{KMMCCmdClassBlockRead, ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}, //CMD14 - BUSTEST_R
{KMMCCmdClassBasic, ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeNone, 0}, //CMD15
{KMMCCmdClassBlockRead, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD16
{KMMCCmdClassBlockRead, ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}, //CMD17
{KMMCCmdClassBlockRead, ECmdTypeADTCS, EDirRead, ETrue, ETrue, ERespTypeR1, 4}, //CMD18
{KMMCCmdClassBlockWrite,ECmdTypeADTCS, EDirWrite, EFalse, EFalse, ERespTypeR1, 4}, //CMD19 - BUSTEST_W
{KMMCCmdClassStreamWrite,ECmdTypeADTCS, EDirWrite, EFalse, ETrue, ERespTypeR1, 4}, //CMD20
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD21
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD22
{KMMCCmdClassBlockRead |
KMMCCmdClassBlockWrite,ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD23
{KMMCCmdClassBlockWrite,ECmdTypeADTCS, EDirWrite, EFalse, EFalse, ERespTypeR1, 4}, //CMD24
{KMMCCmdClassBlockWrite,ECmdTypeADTCS, EDirWrite, ETrue, ETrue, ERespTypeR1, 4}, //CMD25
{KMMCCmdClassBlockWrite,ECmdTypeADTCS, EDirWrite, EFalse, EFalse, ERespTypeR1, 4}, //CMD26
{KMMCCmdClassBlockWrite,ECmdTypeADTCS, EDirWrite, EFalse, EFalse, ERespTypeR1, 4}, //CMD27
{KMMCCmdClassWriteProtection,ECmdTypeACS,EDirNone, EFalse, EFalse, ERespTypeR1B, 4}, //CMD28
{KMMCCmdClassWriteProtection,ECmdTypeACS,EDirNone, EFalse, EFalse, ERespTypeR1B, 4}, //CMD29
{KMMCCmdClassWriteProtection,ECmdTypeADTCS,EDirRead,EFalse, EFalse, ERespTypeR1, 4}, //CMD30
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD31
{KMMCCmdClassErase, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD32
{KMMCCmdClassErase, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD33
{KMMCCmdClassErase, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD34
{KMMCCmdClassErase, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD35
{KMMCCmdClassErase, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD36
{KMMCCmdClassErase, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD37
{KMMCCmdClassErase, ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1B, 4}, //CMD38
{KMMCCmdClassIOMode, ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR4, 4}, //CMD39
{KMMCCmdClassIOMode, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR5, 4}, //CMD40
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD41
{KMMCCmdClassLockCard, ECmdTypeADTCS, EDirWrite, EFalse, EFalse, ERespTypeR1B, 4}, //CMD42
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD43
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD44
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD45
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD46
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD47
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD48
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD49
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD50
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD51
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD52
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD53
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD54
{KMMCCmdClassApplication,ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR1, 4}, //CMD55
{KMMCCmdClassApplication,ECmdTypeADTCS, EDirRBit0, EFalse, EFalse, ERespTypeR1B, 4}, //CMD56
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD57
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD58
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD59
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD60
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD61
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0}, //CMD62
{KMMCCmdClassNone, ECmdTypeUK, EDirNone, EFalse, EFalse, ERespTypeUnknown, 0} //CMD63
};
EXPORT_C void DMMCSession::FillCommandDesc()
/**
* Fills the current command descriptor with the default data according to MMC spec V2.1
*/
{
TMMCCommandDesc& cmd = Command();
cmd.iSpec = CommandTable[cmd.iCommand & KMMCCommandMask];
cmd.iFlags = 0;
cmd.iBytesDone = 0;
}
EXPORT_C void DMMCSession::FillCommandDesc(TMMCCommandEnum aCommand)
/**
* Initialises the current command according to whether it is a normal
* or an application command.
* @param aCommand Contains the command.
*/
{
Command().iCommand = aCommand;
Command().iArgument = 0; // set stuff bits to zero
FillCommandDesc();
}
EXPORT_C void DMMCSession::FillCommandDesc(TMMCCommandEnum aCommand, TMMCArgument anArgument)
/**
* Initialises the current command with an argument according to whether
* it is a normal or an application command.
* @param aCommand Contains the command.
* @param anArgument Specifies the argument.
*/
{
TMMCCommandDesc& cmd = Command();
cmd.iCommand = aCommand;
FillCommandDesc();
cmd.iArgument = anArgument;
}
EXPORT_C void DMMCSession::FillCommandArgs(TMMCArgument anArgument, TUint32 aLength, TUint8* aMemoryP,
TUint32 aBlkLen)
/**
* Initialises the current commands arguments with the specified parameters
* It is necessary to have set the command arguments with this command prior
* to engaging a read/write macro or command.
* @param anArgument Command specific argument.
* @param aLength aLength Total number of bytes to read/write.
* @param aMemoryP Host source/destination address
* @param aBlkLen Block length
*/
{
TMMCCommandDesc& cmd = Command();
cmd.iArgument = anArgument;
cmd.iTotalLength = aLength;
cmd.iDataMemoryP = aMemoryP;
cmd.iBlockLength = aBlkLen;
cmd.iFlags = 0;
}
const TMMCCommandSpec& DMMCSession::FindCommandSpec(const TMMCIdxCommandSpec aSpecs[], TInt aIdx)
/**
* Searches the supplied command specification list for the specification corresponding to the
* supplied command.
* @param aSpecs The command specification list to be searched.
* @param aIdx The requested command.
*/
{
TInt i = 0;
while (aSpecs[i].iIdx != aIdx)
++i;
return aSpecs[i].iSpec;
}
void DMMCSession::SynchBlock(TUint32 aFlag)
//
// Blocks a session synchronously (within scheduler context)
//
{
(void)__e32_atomic_ior_ord32(&iBlockOn, aFlag);
}
void DMMCSession::SynchUnBlock(TUint32 aFlag)
//
// Unblocks a session synchronously (within scheduler context)
//
{
if( (iBlockOn & aFlag) == 0 )
return;
(void)__e32_atomic_and_ord32(&iBlockOn, ~aFlag);
}
EXPORT_C TRCA DMMCSession::CardRCA()
/**
* Checks that the card is still the same and ready
* @return A TRCA object containing the card's RCA (or 0 if the card is not ready)
*/
{
// Rely on 'CardIsGone' bit rather than a CID comparison
if ( iCardP != NULL && iCardP->IsPresent() && !(iState & KMMCSessStateCardIsGone) )
return( iCardP->RCA() );
return(0);
}
#ifdef __EPOC32__
void DMMCSession::ProgramTimerCallBack(TAny* aSessP)
{
__KTRACE_OPT(KPBUS1,Kern::Printf("=mss:pgtcb"));
static_cast<DMMCSession *>(aSessP)->iState |= KMMCSessStateDoDFC;
static_cast<DMMCSession *>(aSessP)->UnBlock(KMMCBlockOnPgmTimer, KMMCErrNone);
}
void DMMCSession::PollTimerCallBack(TAny* aSessP)
{
__KTRACE_OPT(KPBUS1,Kern::Printf("=mss:ptcb"));
static_cast<DMMCSession *>(aSessP)->iState |= KMMCSessStateDoDFC;
static_cast<DMMCSession *>(aSessP)->UnBlock(KMMCBlockOnPollTimer, KMMCErrNone);
}
void DMMCSession::RetryTimerCallBack(TAny* aSessP)
{
__KTRACE_OPT(KPBUS1,Kern::Printf("=mss:rtcb"));
static_cast<DMMCSession *>(aSessP)->iState |= KMMCSessStateDoDFC;
static_cast<DMMCSession *>(aSessP)->UnBlock(KMMCBlockOnRetryTimer, KMMCErrNone);
}
#endif // #ifdef __EPOC32__
EXPORT_C TInt DMMCSession::EpocErrorCode() const
/**
* Returns the last Symbian OS style error code returned in this session.
* The Symbian OS error code is derived from both the last MMC specific exit code MMCExitCode()
* and the last status information from the card (iLastStatus).
* @return Standard Symbian OS error code
*/
{
__KTRACE_OPT(KPBUS1,Kern::Printf("=mss:eee:%08x,%08x", MMCExitCode(), LastStatus().State() ));
struct errorTableEntry
{
TUint32 iMask;
TInt iErrorCode;
};
static const errorTableEntry mmcTable[] =
{
{KMMCErrNotSupported, KErrNotSupported},
{KMMCErrStackNotReady, KErrBadPower},
{KMMCErrArgument, KErrArgument},
{KMMCErrBrokenLock | KMMCErrPowerDown | KMMCErrAbort, KErrAbort},
{KMMCErrNoCard | KMMCErrResponseTimeOut | KMMCErrDataTimeOut |
KMMCErrBusyTimeOut | KMMCErrBusTimeOut, KErrNotReady},
{KMMCErrResponseCRC|KMMCErrDataCRC|KMMCErrCommandCRC, KErrCorrupt},
{KMMCErrLocked, KErrLocked},
{KMMCErrNotFound, KErrNotFound},
{KMMCErrAlreadyExists, KErrAlreadyExists},
{KMMCErrGeneral, KErrGeneral},
{~0UL, KErrUnknown}
};
static const errorTableEntry statusTable[] =
{
{KMMCStatErrOverrun|KMMCStatErrUnderrun|
KMMCStatErrCardECCFailed|KMMCStatErrComCRCError, KErrGeneral},
{KMMCStatErrCSDOverwrite|KMMCStatErrWPViolation, KErrWrite},
{KMMCStatErrLockUnlock, KErrLocked},
{KMMCStatErrIllegalCommand, KErrNotSupported},
{KMMCStatErrEraseParam|KMMCStatErrEraseSeqError|
KMMCStatErrBlockLenError|KMMCStatErrAddressError|
KMMCStatErrOutOfRange, KErrArgument},
{~0UL, KErrUnknown}
};
TUint32 errCode = MMCExitCode();
if( errCode == 0 )
return KErrNone;
const errorTableEntry* ptr = &mmcTable[0];
if( errCode == KMMCErrStatus )
{
ptr = &statusTable[0];
if( (errCode = LastStatus()) == 0 )
return( KErrUnknown );
}
for( ;; )
if( (errCode & ptr->iMask) != 0 )
return( ptr->iErrorCode );
else
ptr++;
}