sl@0: // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include "OstTraceDefinitions.h" sl@0: #ifdef OST_TRACE_COMPILER_IN_USE sl@0: #include "locmedia_ost.h" sl@0: #ifdef __VC32__ sl@0: #pragma warning(disable: 4127) // disabling warning "conditional expression is constant" sl@0: #endif sl@0: #include "sdcardTraces.h" sl@0: #endif sl@0: sl@0: sl@0: // ======== TSDCard ======== sl@0: sl@0: TSDCard::TSDCard() sl@0: : iProtectedAreaSize(0), iPARootDirEnd(KPARootDirEndUnknown) sl@0: { sl@0: // empty sl@0: } sl@0: sl@0: TInt64 TSDCard::DeviceSize64() const sl@0: // sl@0: // returns the SD device size sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( TSDCARD_DEVICESIZE64_ENTRY, this ); sl@0: if(iFlags & KSDCardIsSDCard) sl@0: { sl@0: return (IsHighCapacity()) ? 512 * 1024 * (TInt64)(1 + CSD().CSDField(69, 48)) : TMMCard::DeviceSize64(); sl@0: } sl@0: sl@0: return(TMMCard::DeviceSize64()); sl@0: } sl@0: sl@0: TUint32 TSDCard::PreferredWriteGroupLength() const sl@0: // sl@0: // return SD erase sector size, (SECTOR_SIZE + 1) * 2 ** WRITE_BLK_LEN sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( TSDCARD_PREFERREDWRITEGROUPLENGTH_ENTRY, this ); sl@0: if(iFlags & KSDCardIsSDCard) sl@0: { sl@0: TSDCSD sdcsd(CSD()); sl@0: return (sdcsd.SDSectorSize() + 1) * (1 << sdcsd.WriteBlLen()); sl@0: } sl@0: sl@0: return(TMMCard::PreferredWriteGroupLength()); sl@0: } sl@0: sl@0: TInt TSDCard::GetFormatInfo(TLDFormatInfo& /*aFormatInfo*/) const sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TUint32 TSDCard::MinEraseSectorSize() const sl@0: { sl@0: if(iFlags&KSDCardIsSDCard) sl@0: { sl@0: TSDCSD sdcsd(CSD()); sl@0: if (sdcsd.SDEraseBlkEn()) sl@0: return sdcsd.WriteBlockLength(); // raised logarithm sl@0: else sl@0: return (sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength(); sl@0: } sl@0: sl@0: return TMMCard::MinEraseSectorSize(); sl@0: } sl@0: sl@0: sl@0: const TUint32 KEraseSectorSizeShift = 8; // KEraseSectorSizeShift determines the multiple of the sector size sl@0: // that can be erased in one operation sl@0: TUint32 TSDCard::EraseSectorSize() const sl@0: { sl@0: if(iFlags&KSDCardIsSDCard) sl@0: { sl@0: TSDCSD sdcsd(CSD()); sl@0: return ((sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength()) << KEraseSectorSizeShift; sl@0: } sl@0: sl@0: return TMMCard::EraseSectorSize(); sl@0: } sl@0: sl@0: const TInt KDefaultBlockLen = 9; // 2^9 = 512 bytes sl@0: const TInt KDefaultBlockLenInBytes = 1 << KDefaultBlockLen; // 2^9 = 512 bytes sl@0: const TInt KTwoGbyteSDBlockLen = 10; // 2^10 = 1024 bytes sl@0: const TInt KFourGbyteSDBlockLen = 11; // 2^11 = 2048 bytes sl@0: sl@0: TInt TSDCard::GetEraseInfo(TMMCEraseInfo& aEraseInfo) const sl@0: // sl@0: // Return info. on erase services for this card sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( TSDCARD_GETERASEINFO_ENTRY, this ); sl@0: sl@0: // SD Controllers support MMC cards too. Check if we are really dealing with an SD card sl@0: if(!(iFlags&KSDCardIsSDCard)) sl@0: return(TMMCard::GetEraseInfo(aEraseInfo)); sl@0: sl@0: if (CSD().CCC() & KMMCCmdClassErase) sl@0: { sl@0: // This card supports erase cmds. However, SD cards don't support Erase Group commands (i.e. CMD35, CMD36). sl@0: OstTrace0( TRACE_INTERNALS, TSDCARD_GETERASEINFO, "Card supports erase class commands" ); sl@0: aEraseInfo.iEraseFlags=KMMCEraseClassCmdsSupported; sl@0: sl@0: // Return the preferred size to be used as the unit for erase operations. sl@0: TSDCSD sdcsd(CSD()); sl@0: TUint32 prefSize=((sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength()); sl@0: prefSize<<=KEraseSectorSizeShift; // Use multiples of the sector size for each erase operation sl@0: aEraseInfo.iPreferredEraseUnitSize=prefSize; sl@0: sl@0: // Return the smallest size that can be used as the unit for erase operations sl@0: if (sdcsd.SDEraseBlkEn()) sl@0: { sl@0: aEraseInfo.iMinEraseSectorSize = KDefaultBlockLenInBytes; sl@0: } sl@0: else sl@0: { sl@0: aEraseInfo.iMinEraseSectorSize=(sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength(); sl@0: } sl@0: } sl@0: else sl@0: aEraseInfo.iEraseFlags=0; sl@0: sl@0: OstTraceFunctionExitExt( TSDCARD_GETERASEINFO_EXIT, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt TSDCard::MaxReadBlLen() const sl@0: /** sl@0: * Returns the maximum read block length supported by the card encoded as a logarithm sl@0: * Normally this is the same as the READ_BL_LEN field in the CSD register, sl@0: * but for high capacity cards (> 2GB) this is set to a maximum of 512 bytes, sl@0: * if possible, to try to avoid compatibility issues. sl@0: */ sl@0: { sl@0: OstTraceFunctionEntry1( TSDCARD_MAXREADBLLEN_ENTRY, this ); sl@0: if (IsSDCard()) sl@0: { sl@0: TInt blkLenLog2 = CSD().ReadBlLen(); sl@0: if (blkLenLog2 == KTwoGbyteSDBlockLen || blkLenLog2 == KFourGbyteSDBlockLen) sl@0: { sl@0: // The SD card spec. makes a special case for 2GByte cards, sl@0: // ...and some manufacturers apply the same method to support 4G cards sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl > 2GB SD")); sl@0: OstTrace0( TRACE_INTERNALS, TSDCARD_MAXREADBLLEN, "SD Card > 2GB" ); sl@0: blkLenLog2 = KDefaultBlockLen; sl@0: } sl@0: OstTraceFunctionExitExt( TSDCARD_MAXREADBLLEN_EXIT, this, blkLenLog2 ); sl@0: return blkLenLog2; sl@0: } sl@0: else // MMC card sl@0: { sl@0: TInt ret = TMMCard::MaxReadBlLen(); sl@0: OstTraceFunctionExitExt( DUP1_TSDCARD_MAXREADBLLEN_EXIT, this, ret ); sl@0: return ret; sl@0: } sl@0: } sl@0: sl@0: TInt TSDCard::MaxWriteBlLen() const sl@0: /** sl@0: * Returns the maximum write block length supported by the card encoded as a logarithm sl@0: * Normally this is the same as the WRITE_BL_LEN field in the CSD register, sl@0: * but for high capacity cards (> 2GB) this is set to a maximum of 512 bytes, sl@0: * if possible, to try to avoid compatibility issues. sl@0: */ sl@0: { sl@0: OstTraceFunctionEntry1( TSDCARD_MAXWRITEBLLEN_ENTRY, this ); sl@0: if (IsSDCard()) sl@0: { sl@0: TInt blkLenLog2 = CSD().WriteBlLen(); sl@0: if (blkLenLog2 == KTwoGbyteSDBlockLen || blkLenLog2 == KFourGbyteSDBlockLen) sl@0: { sl@0: // The SD card spec. makes a special case for 2GByte cards, sl@0: // ...and some manufacturers apply the same method to support 4G cards sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mwbl > 2GB SD")); sl@0: OstTrace0( TRACE_INTERNALS, TSDCARD_MAXWRITEBLLEN, "SD Card > 2GB" ); sl@0: blkLenLog2 = KDefaultBlockLen; sl@0: } sl@0: OstTraceFunctionExitExt( TSDCARD_MAXWRITEBLLEN_EXIT, this, blkLenLog2 ); sl@0: return blkLenLog2; sl@0: } sl@0: else // MMC card sl@0: { sl@0: TInt ret = TMMCard::MaxWriteBlLen(); sl@0: OstTraceFunctionExitExt( DUP1_TSDCARD_MAXWRITEBLLEN_EXIT, this, ret ); sl@0: return ret; sl@0: } sl@0: } sl@0: sl@0: TUint TSDCard::MaxTranSpeedInKilohertz() const sl@0: /** sl@0: * Returns the maximum supported clock rate for the card, in Kilohertz. sl@0: * @return Speed, in Kilohertz sl@0: */ sl@0: { sl@0: OstTraceFunctionEntry1( TSDCARD_MAXTRANSPEEDINKILOHERTZ_ENTRY, this ); sl@0: TUint maxClk = TMMCard::MaxTranSpeedInKilohertz(); sl@0: sl@0: if (IsSDCard()) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("\t >TSDCard(%d): MaxTranSpeedInKilohertz: %d",(iIndex-1),maxClk)); sl@0: sl@0: #ifdef _DEBUG sl@0: //MaxClk for SD should only be either 25000KHz or 50000KHz sl@0: if ( (maxClk != KSDDTClk25MHz) && (maxClk != KSDDTClk50MHz) ) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Non-Compliant DT Clock")); sl@0: OstTrace0( TRACE_INTERNALS, TSDCARD_MAXTRANSPEEDINKILOHERTZ, "Non-Compliant DT Clock" ); sl@0: } sl@0: #endif sl@0: if (maxClk > KSDDTClk50MHz) sl@0: { sl@0: //Clock rate exceeds SD possible max clock rate sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Tuning DT Clock down to 50MHz")); sl@0: OstTrace0( TRACE_INTERNALS, TSDCARD_MAXTRANSPEEDINKILOHERTZ1, "Tuning DT Clock down to 50MHz" ); sl@0: maxClk = KSDDTClk50MHz; sl@0: } sl@0: } sl@0: sl@0: OstTraceFunctionExitExt( TSDCARD_MAXTRANSPEEDINKILOHERTZ_EXIT, this, maxClk ); sl@0: return maxClk; sl@0: } sl@0: sl@0: // ======== TSDCardArray ======== sl@0: sl@0: EXPORT_C TInt TSDCardArray::AllocCards() sl@0: // sl@0: // allocate TSDCard objects for iCards and iNewCardsArray. This function sl@0: // is called at bootup as part of stack allocation so there is no cleanup sl@0: // if it fails. sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( TSDCARDARRAY_ALLOCCARDS_ENTRY, this ); sl@0: for (TInt i = 0; i < (TInt) KMaxMMCardsPerStack; ++i) sl@0: { sl@0: // zeroing the card data used to be implicit because embedded in sl@0: // CBase-derived DMMCStack. sl@0: if ((iCards[i] = new TSDCard) == 0) sl@0: { sl@0: OstTraceFunctionExitExt( TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: iCards[i]->iUsingSessionP = 0; sl@0: if ((iNewCards[i] = new TSDCard) == 0) sl@0: { sl@0: OstTraceFunctionExitExt( DUP1_TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: } sl@0: sl@0: OstTraceFunctionExitExt( DUP2_TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void TSDCardArray::AddCardSDMode(TUint aCardNumber,const TUint8* aCID,TRCA* aNewRCA) sl@0: // sl@0: // Add an MMC card straight to the main card array in slot 'aCardNumber'. Save sl@0: // the CID value in the slot. Return a RCA for the card. sl@0: // sl@0: { sl@0: OstTraceFunctionEntryExt( TSDCARDARRAY_ADDCARDSDMODE_ENTRY, this ); sl@0: sl@0: TRCA rca=0; sl@0: sl@0: // First, lets check if the same card was here before. If it was, keep the same RCA sl@0: if (Card(aCardNumber).IsPresent() && Card(aCardNumber).iCID==aCID) sl@0: rca=Card(aCardNumber).iRCA; sl@0: else sl@0: { sl@0: // Allocate and new RCA and store the CID in the slot selected sl@0: __ASSERT_ALWAYS( (rca=iOwningStack->iRCAPool.GetFreeRCA())!=0,DMMCSocket::Panic(DMMCSocket::EMMCNoFreeRCA) ); sl@0: Card(aCardNumber).iCID=aCID; sl@0: if ( Card(aCardNumber).iRCA != 0 ) sl@0: iOwningStack->iRCAPool.UnlockRCA(Card(aCardNumber).iRCA); sl@0: Card(aCardNumber).iRCA=rca; sl@0: iOwningStack->iRCAPool.LockRCA(Card(aCardNumber).iRCA); sl@0: } sl@0: sl@0: Card(aCardNumber).iIndex=(aCardNumber+1); // Mark card as being present sl@0: *aNewRCA=rca; sl@0: OstTraceFunctionExit1( TSDCARDARRAY_ADDCARDSDMODE_EXIT, this ); sl@0: } sl@0: sl@0: TInt TSDCardArray::StoreRCAIfUnique(TUint aCardNumber,TRCA& anRCA) sl@0: // sl@0: // Check that no other array element has the same RCA value 'anRCA'. If no sl@0: // no duplication then store in slot 'aCardNumber'. sl@0: // sl@0: { sl@0: OstTraceExt3(TRACE_FLOW, TSDCARDARRAY_STORERCAIFUNIQUE_ENTRY ,"TSDCardArray::StoreRCAIfUnique;aCardNumber=%x;anRCA=%x;this=%x", aCardNumber, (TUint) anRCA, (TUint) this); sl@0: sl@0: if (anRCA==0) sl@0: { sl@0: OstTraceFunctionExitExt( TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrGeneral ); sl@0: return KErrGeneral; sl@0: } sl@0: Card(aCardNumber).iRCA=0; sl@0: sl@0: // Now let's look if we've seen this card before sl@0: for ( TUint i=0 ; iiMaxCardsInStack ; i++ ) sl@0: { sl@0: if ( Card(i).IsPresent() && Card(i).iRCA==anRCA ) sl@0: { sl@0: OstTraceFunctionExitExt( DUP1_TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrInUse ); sl@0: return KErrInUse; sl@0: } sl@0: } sl@0: Card(aCardNumber).iRCA=anRCA; sl@0: Card(aCardNumber).iIndex=(aCardNumber+1); // Mark card as being present sl@0: OstTraceFunctionExitExt( DUP2_TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: EXPORT_C void TSDCardArray::DeclareCardAsGone(TUint aCardNumber) sl@0: // sl@0: // reset SD specific fields to initial values and then reset generic MultiMediaCard sl@0: // sl@0: { sl@0: OstTraceFunctionEntryExt( TSDCARDARRAY_DECLARECARDASGONE_ENTRY, this ); sl@0: Card(aCardNumber).SetBusWidth(1); sl@0: TMMCardArray::DeclareCardAsGone(aCardNumber); sl@0: OstTraceFunctionExit1( TSDCARDARRAY_DECLARECARDASGONE_EXIT, this ); sl@0: } sl@0: sl@0: // ======== DSDSession ======== sl@0: sl@0: void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc, TSDAppCmd aCmd) sl@0: { sl@0: OstTraceFunctionEntry0( DSDSESSION_FILLAPPCOMMANDDESC_ENTRY ); sl@0: aDesc.iCommand = (TMMCCommandEnum) aCmd; sl@0: aDesc.iArgument = 0; // set stuff bits to zero sl@0: FillAppCommandDesc(aDesc); sl@0: OstTraceFunctionExit0( DSDSESSION_FILLAPPCOMMANDDESC_EXIT ); sl@0: } sl@0: sl@0: void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc, TSDAppCmd aCmd, TMMCArgument aArg) sl@0: { sl@0: OstTraceFunctionEntry0( DUP1_DSDSESSION_FILLAPPCOMMANDDESC_ENTRY ); sl@0: aDesc.iCommand = (TMMCCommandEnum) aCmd; sl@0: aDesc.iArgument = aArg; sl@0: FillAppCommandDesc(aDesc); sl@0: OstTraceFunctionExit0( DUP1_DSDSESSION_FILLAPPCOMMANDDESC_EXIT ); sl@0: } sl@0: sl@0: const TUint32 CCA = KMMCCmdClassApplication; sl@0: const TMMCIdxCommandSpec AppCmdSpecTable[] = sl@0: { // Class Type Dir MBlk StopT Rsp Type Len sl@0: {ESDACmdSetBusWidth, {CCA,ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD6 sl@0: {ESDACmdSDStatus, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD13 sl@0: {ESDACmdSendNumWrBlocks, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD22 sl@0: {ESDACmdSetWrBlkEraseCount, {CCA,ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD23 sl@0: {ESDACmdSDAppOpCond, {CCA,ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR3, 4}}, //ACMD41 sl@0: {ESDACmdSetClrCardDetect, {CCA,ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD42 sl@0: {ESDACmdSendSCR, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}} //ACMD51 sl@0: }; sl@0: sl@0: void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc) sl@0: { sl@0: OstTraceFunctionEntry0( DUP2_DSDSESSION_FILLAPPCOMMANDDESC_ENTRY ); sl@0: aDesc.iSpec = FindCommandSpec(AppCmdSpecTable, aDesc.iCommand); sl@0: aDesc.iFlags = 0; sl@0: aDesc.iBytesDone = 0; sl@0: OstTraceFunctionExit0( DUP2_DSDSESSION_FILLAPPCOMMANDDESC_EXIT ); sl@0: } sl@0: sl@0: const TMMCIdxCommandSpec SdSpecificCmdSpecTable[] = sl@0: /** sl@0: * SD Specific Command Table sl@0: * sl@0: * - Some commands defined in the SD specification overload those defined in the MMC specification. sl@0: * This table contains the SD specific versions of those commands. sl@0: */ sl@0: { sl@0: // Class Type Dir MBlk StopT Rsp Type Len sl@0: {ESDCmdSendRelativeAddress, {KMMCCmdClassBasic, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR6, 4}}, // CMD3 : SEND_RELATIVE_ADDRESS sl@0: {ESDCmdSwitchFunction, {KMMCCmdClassSwitch,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, // CMD6 : SWITCH_FUNCTION sl@0: {ESDCmdSendIfCond, {KMMCCmdClassBasic, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR7, 4}} // CMD8 : SEND_IF_COND sl@0: }; sl@0: sl@0: void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc, TSDSpecificCmd aCmd, TMMCArgument aArg) sl@0: { sl@0: OstTraceFunctionEntry0( DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY ); sl@0: aDesc.iCommand = (TMMCCommandEnum) aCmd; sl@0: aDesc.iArgument = aArg; sl@0: FillSdSpecificCommandDesc(aDesc); sl@0: OstTraceFunctionExit0( DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT ); sl@0: } sl@0: sl@0: void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc, TSDSpecificCmd aCmd) sl@0: { sl@0: OstTraceFunctionEntry0( DUP1_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY ); sl@0: aDesc.iCommand = (TMMCCommandEnum) aCmd; sl@0: aDesc.iArgument = 0; // set stuff bits to zero sl@0: FillSdSpecificCommandDesc(aDesc); sl@0: OstTraceFunctionExit0( DUP1_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT ); sl@0: } sl@0: sl@0: void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc) sl@0: { sl@0: OstTraceFunctionEntry0( DUP2_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY ); sl@0: aDesc.iSpec = FindCommandSpec(SdSpecificCmdSpecTable, aDesc.iCommand); sl@0: aDesc.iFlags = 0; sl@0: aDesc.iBytesDone = 0; sl@0: OstTraceFunctionExit0( DUP2_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT ); sl@0: } sl@0: sl@0: sl@0: // ======== DSDStack ======== sl@0: sl@0: EXPORT_C TInt DSDStack::Init() sl@0: { sl@0: OstTraceFunctionEntry1( DSDSTACK_INIT_ENTRY, this ); sl@0: TInt ret = DMMCStack::Init(); sl@0: OstTraceFunctionExitExt( DSDSTACK_INIT_EXIT, this, ret ); sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: const TInt KMaxRCASendLoops=3; sl@0: const TUint KSDMaxPollAttempts=25; sl@0: EXPORT_C TMMCErr DSDStack::AcquireStackSM() sl@0: // sl@0: // This macro acquires new cards in an SD Card - star topology stack. sl@0: // This means each card has its own CMD and DAT lines and can be addressed sl@0: // individually by the Controller in turn. Commands can also be broadcast sl@0: // simultaneously to the entire stack. sl@0: // It starts with the Controller reading the operating conditions of each sl@0: // card in the stack (SEND_OP_COND - ACMD41). Then, the following sl@0: // initialisation sequence is performed to each card in turn:- sl@0: // New cards in the stack are identified (ALL_SEND_CID - CMD2) and each one sl@0: // is requested to publish a relative card address (SEND_RCA - CMD3). Finally, sl@0: // the card specific data (SEND_CSD - CMD9) is read from each card. sl@0: // Note that the initialization of MMC cards are supported by this function sl@0: // if they are encountered. These require a slightly different init. procdure. sl@0: // sl@0: { sl@0: enum states sl@0: { sl@0: EStBegin=0, sl@0: EStNextFullRange, sl@0: EStSendCIDIssued, sl@0: EStIssueSendRCA, sl@0: EStSendRCACheck, sl@0: EStRCADone, sl@0: EStMoreCardsCheck, sl@0: EStEnd sl@0: }; sl@0: sl@0: DMMCSession& s=Session(); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM, "Current session = 0x%x", &s ); sl@0: sl@0: SMF_BEGIN sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM1, "EStBegin" ); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf(">DSDStack::AcquireStackSM()")); sl@0: sl@0: iRCAPool.ReleaseUnlocked(); sl@0: iCxCardCount=0; // Reset current card number sl@0: sl@0: SMF_STATE(EStNextFullRange) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM2, "EStNextFullRange" ); sl@0: iCxCardType = ESDCardTypeUnknown; sl@0: sl@0: AddressCard(iCxCardCount); // Address the next card sl@0: sl@0: // Before issueing commands, see if there's actually a card present sl@0: if (!CardDetect(iCxCardCount)) sl@0: SMF_GOTOS(EStMoreCardsCheck) sl@0: sl@0: m.SetTraps(KMMCErrResponseTimeOut); sl@0: SMF_INVOKES(InitialiseMemoryCardSMST, EStSendCIDIssued) sl@0: sl@0: SMF_STATE(EStSendCIDIssued) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM3, "EStSendCIDIssued" ); sl@0: if( !err ) sl@0: { sl@0: // The card responded with a CID. We need to initialise the sl@0: // appropriate entry in the card array with the CID. sl@0: if (iCxCardType==ESDCardTypeIsSD) sl@0: { sl@0: // Now prepare to recieve an RCA from to the card sl@0: CardArray().CardP(iCxCardCount)->iCID=s.ResponseP(); sl@0: DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSendRelativeAddress,0); // SEND_RCA with argument just stuff bits sl@0: sl@0: m.ResetTraps(); sl@0: iCxPollRetryCount=0; // Init count of send RCA attempts sl@0: SMF_GOTOS(EStIssueSendRCA) sl@0: } sl@0: else sl@0: { sl@0: // The card array allocates an RCA, either the old RCA sl@0: // if we have seen this card before, or a new one. sl@0: TRCA rca; sl@0: CardArray().AddCardSDMode(iCxCardCount,s.ResponseP(),&rca); sl@0: sl@0: // Now assign the new RCA to the card sl@0: s.FillCommandDesc(ECmdSetRelativeAddr,TMMCArgument(rca)); sl@0: m.ResetTraps(); sl@0: SMF_INVOKES(ExecCommandSMST,EStRCADone) sl@0: } sl@0: } sl@0: else sl@0: { sl@0: m.ResetTraps(); sl@0: SMF_GOTOS(EStMoreCardsCheck) // Timed out, try the next card slot sl@0: } sl@0: sl@0: SMF_STATE(EStIssueSendRCA) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM4, "EStIssueSendRCA" ); sl@0: SMF_INVOKES(ExecCommandSMST,EStSendRCACheck) sl@0: sl@0: SMF_STATE(EStSendRCACheck) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM5, "EStSendRCACheck" ); sl@0: // We need to check that the RCA recieved from the card doesn't clash sl@0: // with any others in this stack. RCA is first 2 bytes of response buffer (in big endian) sl@0: TRCA rca=(TUint16)((s.ResponseP()[0]<<8) | s.ResponseP()[1]); sl@0: if (CardArray().StoreRCAIfUnique(iCxCardCount,rca)!=KErrNone) sl@0: SMF_GOTOS( ((++iCxPollRetryCountDSDStack::AcquireStackSM(): More Cards to check: %d",iCxCardCount)); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_ACQUIRESTACKSM8, "More Cards to check: iCxCardCount=%d", iCxCardCount ); sl@0: SMF_GOTOS(EStNextFullRange) sl@0: } sl@0: else sl@0: { sl@0: AddressCard(KBroadcastToAllCards); // Set back to broadcast mode sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("(aStackP)->InitialiseMemoryCardSM(); } sl@0: sl@0: sl@0: TMMCErr DSDStack::InitialiseMemoryCardSM() sl@0: /** sl@0: */ sl@0: { sl@0: enum states sl@0: { sl@0: EStBegin=0, sl@0: EStSendInterfaceCondition, sl@0: EStSentInterfaceCondition, sl@0: EStSetFullRangeCmd, sl@0: EStCheckForFullRangeCmd41Timeout, sl@0: EStSentAppCommandBeforeCheckVoltage, sl@0: EStCheckVoltage, sl@0: EStFullRangeDone, sl@0: EStSetRangeCmd, sl@0: EStCheckForRangeCmd41Timeout, sl@0: EStSetRangeBusyCheck, sl@0: EStCIDCmd, sl@0: EStSendCIDIssued, sl@0: EStEnd sl@0: }; sl@0: sl@0: DMMCSession& s=Session(); sl@0: DMMCPsu* psu=(DMMCPsu*)MMCSocket()->iVcc; sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM, "Current session = 0x%x", &s ); sl@0: sl@0: static const TUint32 KCmd8Param = 0x0100 | 0x00AA; // Voltage supplied : 2.7-3.6V, Check Pattern 10101010b sl@0: static const TUint32 KCmd8CheckMask = 0x00000FFF; sl@0: sl@0: SMF_BEGIN sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM1, "EStBegin" ); sl@0: iCxCardType = ESDCardTypeUnknown; sl@0: s.iCardP = NULL; // This stops ExecCommandSM() from setting old RCA when sending CMD55 sl@0: sl@0: // Send CMD0 to initialise memory sl@0: SMF_INVOKES(GoIdleSMST, EStSendInterfaceCondition); sl@0: sl@0: SMF_STATE(EStSendInterfaceCondition) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM2, "EStSendInterfaceCondition" ); sl@0: iCxPollRetryCount=0; // Reset max number of poll attempts on card busy sl@0: iConfig.SetPollAttempts(KSDMaxPollAttempts); // Increase card busy timeout to 1 Sec for SD Cards sl@0: sl@0: iConfig.RemoveMode( KMMCModeEnableTimeOutRetry ); // Temporarily disable timeout retries - since we use a timeout event to distinguish between MMC and SD sl@0: sl@0: DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSendIfCond, KCmd8Param); sl@0: sl@0: // SD2.0 defines CMD8 as having a new response type - R7 sl@0: // if the PSL doesn't indicate support for R7, use R1 instead sl@0: if (!(MMCSocket()->MachineInfo().iFlags & TMMCMachineInfo::ESupportsR7)) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("R7 not supported.")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM3, "R7 not supported" ); sl@0: Command().iSpec.iResponseType = ERespTypeR1; sl@0: } sl@0: sl@0: sl@0: m.SetTraps(KMMCErrAll); sl@0: SMF_INVOKES(ExecCommandSMST, EStSentInterfaceCondition) sl@0: sl@0: SMF_STATE(EStSentInterfaceCondition) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM4, "EStSentInterfaceCondition" ); sl@0: if (err == KMMCErrNone) sl@0: { sl@0: // Check the response for voltage and check pattern sl@0: const TUint32 status = TMMC::BigEndian32(s.ResponseP()); sl@0: if((status & KCmd8CheckMask) == KCmd8Param) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("Found v2 card.")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM5, "Found v2 card" ); sl@0: iCurrentOpRange |= KMMCOCRAccessModeHCS; sl@0: } sl@0: else sl@0: { sl@0: // Pattern Mis-match, card does not support the specified voltage range sl@0: OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT, this, (TInt) KMMCErrNotSupported ); sl@0: return KMMCErrNotSupported; sl@0: } sl@0: sl@0: SMF_GOTOS(EStCheckVoltage); sl@0: } sl@0: sl@0: // Go idle again after CMD8 failure sl@0: SMF_INVOKES(GoIdleSMST, EStCheckVoltage); sl@0: sl@0: sl@0: SMF_STATE(EStCheckVoltage) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM6, "EStCheckVoltage" ); sl@0: // If platform doesn't support an adjustable voltage PSU then there's no sl@0: // point in doing a full range for its supported range. To support range sl@0: // checking on a multi-card stack would require a complete scan of all sl@0: // cards before actually setting the range. This would over-complicate things sl@0: // and make the more normal single card/none adjustable cases less efficient. sl@0: if ( !(psu->VoltageSupported()&KMMCAdjustableOpVoltage) || iMaxCardsInStack>1) sl@0: { sl@0: // if the PSU isn't adjustable then it can't support low voltage mode sl@0: iCurrentOpRange&= ~KMMCOCRLowVoltage; sl@0: sl@0: SMF_GOTOS(EStSetRangeCmd) sl@0: } sl@0: sl@0: SMF_STATE(EStSetFullRangeCmd) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM7, "EStSetFullRangeCmd" ); sl@0: // Issue ACMD41/CMD1 with omitted voltage range sl@0: if (iCxCardType==ESDCardTypeIsMMC) sl@0: { sl@0: s.FillCommandDesc(ECmdSendOpCond, KMMCOCRAccessModeHCS | KMMCOCRBusy); // Full range + Sector Access + Busy bit (iArgument==KBit31) sl@0: SMF_NEXTS(EStFullRangeDone) sl@0: } sl@0: else sl@0: { sl@0: DSDSession::FillAppCommandDesc(Command(), ESDACmdSDAppOpCond, TMMCArgument(0)); sl@0: SMF_NEXTS(EStCheckForFullRangeCmd41Timeout) sl@0: } sl@0: sl@0: m.SetTraps(KMMCErrResponseTimeOut); sl@0: SMF_CALL(ExecCommandSMST) sl@0: sl@0: SMF_STATE(EStCheckForFullRangeCmd41Timeout) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM8, "EStCheckForFullRangeCmd41Timeout" ); sl@0: if (err==KMMCErrResponseTimeOut) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("ACMD 41 not supported - Assuming MMC")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM9, "ACMD 41 not supported - Assuming MMC" ); sl@0: iCxCardType=ESDCardTypeIsMMC; sl@0: sl@0: // Send CMD0 to re-initialise the card - otherwise we may get sl@0: // KMMCStatErrIllegalCommand returned for the next command sl@0: // expecting an R1 response. NB The SD spec recommends ignoring the error sl@0: // whereas the SDIO spec recommends this approach (ignoring the error sl@0: // would be difficult to code anyway, since by then we're no longer sl@0: // in this state machine). sl@0: SMF_INVOKES(GoIdleSMST, EStSetFullRangeCmd); // Repeat - but using CMD1 sl@0: } sl@0: else sl@0: { sl@0: // No response timeout - so it must be an SD Card sl@0: (CardArray().CardP(iCxCardCount)->iFlags)|=KSDCardIsSDCard; sl@0: iCxCardType=ESDCardTypeIsSD; sl@0: } sl@0: sl@0: SMF_STATE(EStFullRangeDone) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM10, "EStFullRangeDone" ); sl@0: if (!err) sl@0: { sl@0: // Card responded with Op range - evaluate the common subset with the current setting. sl@0: // Dont worry about the busy bit for now, we'll check that when we repeat the command sl@0: const TUint32 range = (iCurrentOpRange & ~KMMCOCRAccessModeHCS) & (TMMC::BigEndian32(s.ResponseP()) & ~KMMCOCRBusy); sl@0: if(range == 0) sl@0: { sl@0: OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT1, this, (TInt) KMMCErrNotSupported ); sl@0: return KMMCErrNotSupported; // Card is incompatible with our h/w sl@0: } sl@0: iCurrentOpRange = range | (iCurrentOpRange & KMMCOCRAccessModeHCS); sl@0: } sl@0: sl@0: // Repeat SEND_OP_COND this time setting Current Op Range sl@0: if (iCxCardType==ESDCardTypeIsMMC) sl@0: { sl@0: // If platform and the card both support low voltage mode (1.65 - 1.95v), switch sl@0: // NB If this fails then there is no recovery. sl@0: if (iCurrentOpRange & KMMCOCRLowVoltage) sl@0: { sl@0: iCurrentOpRange = KMMCOCRLowVoltage; sl@0: SMF_INVOKES( SwitchToLowVoltageSMST, EStSetRangeCmd ) sl@0: } sl@0: } sl@0: sl@0: SMF_STATE(EStSetRangeCmd) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM11, "EStSetRangeCmd" ); sl@0: // Issue ACMD41/CMD1 with voltage range sl@0: if (iCxCardType==ESDCardTypeIsMMC) sl@0: { sl@0: s.FillCommandDesc(ECmdSendOpCond,(iCurrentOpRange | KMMCOCRAccessModeHCS | KMMCOCRBusy)); // Range supported + Sector Access Busy bit (iArgument==KBit31) sl@0: SMF_NEXTS(EStSetRangeBusyCheck) sl@0: } sl@0: else sl@0: { sl@0: TUint arg = (iCurrentOpRange & ~KMMCOCRAccessModeHCS); // Range supported sl@0: if((iCurrentOpRange & KMMCOCRAccessModeHCS) != 0) sl@0: { sl@0: arg |= KMMCOCRAccessModeHCS; sl@0: } sl@0: DSDSession::FillAppCommandDesc(Command(), ESDACmdSDAppOpCond, arg); sl@0: SMF_NEXTS((iCxCardType == ESDCardTypeUnknown)? EStCheckForRangeCmd41Timeout : EStSetRangeBusyCheck) sl@0: } sl@0: sl@0: m.SetTraps(KMMCErrResponseTimeOut); sl@0: SMF_CALL(ExecCommandSMST) sl@0: sl@0: SMF_STATE(EStCheckForRangeCmd41Timeout) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM12, "EStCheckForRangeCmd41Timeout" ); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct:%d", err)); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM13, "err=%d", (TInt) err); sl@0: if (err==KMMCErrResponseTimeOut) sl@0: { sl@0: iCxCardType=ESDCardTypeIsMMC; sl@0: // Send CMD0 to re-initialise the card - otherwise we may get sl@0: // KMMCStatErrIllegalCommand returned for the next command sl@0: // expecting an R1 response. NB The SD spec recommends ignoring the error sl@0: // whereas the SDIO spec recommends this approach (ignoring the error sl@0: // would be difficult to code anyway, since by then we're no longer sl@0: // in this state machine). sl@0: SMF_INVOKES(GoIdleSMST, EStSetRangeCmd); // Repeat - but using CMD1 sl@0: } sl@0: else sl@0: { sl@0: // No response timeout - so it must be an SD Card sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct2:%x", iCardArray)); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct3:%x", iCxCardCount)); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct4:%x", CardArray().CardP(iCxCardCount))); sl@0: OstTraceExt3(TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM14, "iCardArray=0x%x;iCxCardCount=%d;CardArray().CardP(iCxCardCount)=%d", (TUint) iCardArray, (TInt) iCxCardCount, (TInt) CardArray().CardP(iCxCardCount)); sl@0: sl@0: (CardArray().CardP(iCxCardCount)->iFlags)|=KSDCardIsSDCard; sl@0: iCxCardType=ESDCardTypeIsSD; sl@0: } sl@0: sl@0: SMF_STATE(EStSetRangeBusyCheck) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM15, "EStSetRangeBusyCheck" ); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:src:%d",iCxCardType)); // 1:MMC, 2:SD sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM16, "iCxCardType=%d", iCxCardType); sl@0: sl@0: if ( !err ) sl@0: { sl@0: const TUint32 ocrResponse = TMMC::BigEndian32(s.ResponseP()); sl@0: sl@0: if ((ocrResponse & KMMCOCRBusy) == 0) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("-sd:upd:bsy")); sl@0: // Card is still busy powering up. Check if we should timeout sl@0: if ( ++iCxPollRetryCount > iConfig.OpCondBusyTimeout() ) sl@0: { sl@0: __KTRACE_OPT2(KPBUS1, KPANIC, Kern::Printf("-sd:ocr busy timed out")); sl@0: OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT2, this, (TInt) KMMCErrBusTimeOut ); sl@0: return KMMCErrBusTimeOut; sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: if ( iCxPollRetryCount > KMMCSpecOpCondBusyTimeout ) sl@0: { sl@0: __KTRACE_OPT2(KPBUS1, KPANIC, Kern::Printf("-sd:ocr exceeded spec timeout!! (%d ms)", (iCxPollRetryCount*KMMCRetryGapInMilliseconds))); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM17, "Exceeded spec timeout (%d ms)", (iCxPollRetryCount*KMMCRetryGapInMilliseconds)); sl@0: } sl@0: #endif sl@0: m.ResetTraps(); sl@0: sl@0: SMF_INVOKES(RetryGapTimerSMST,EStSetRangeCmd) sl@0: } sl@0: else sl@0: { sl@0: if(ocrResponse & KMMCOCRAccessModeHCS) sl@0: { sl@0: CardArray().CardP(iCxCardCount)->iFlags |= KMMCardIsHighCapacity; sl@0: #ifdef _DEBUG sl@0: if(iCxCardType == ESDCardTypeIsSD) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("Found large SD card.")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM18, "Found large SD card" ); sl@0: } sl@0: else if(iCxCardType == ESDCardTypeIsMMC) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("Found large MMC card.")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM19, "Found large MMC card" ); sl@0: } sl@0: #endif sl@0: } sl@0: } sl@0: } sl@0: sl@0: // Restore original settings sl@0: iConfig.SetMode( EffectiveModes(s.iConfig) & KMMCModeEnableTimeOutRetry ); sl@0: iConfig.SetPollAttempts(KMMCMaxPollAttempts); sl@0: sl@0: // All cards are now ready and notified of the voltage range - ask ASSP to set it up sl@0: if (iCxCardType==ESDCardTypeIsMMC) sl@0: { sl@0: iCurrentOpRange &= ~KMMCOCRAccessModeMask; sl@0: } sl@0: else sl@0: { sl@0: iCurrentOpRange &= ~KMMCOCRAccessModeHCS; sl@0: } sl@0: sl@0: psu->SetVoltage(iCurrentOpRange); sl@0: if (psu->SetState(EPsuOnFull) != KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT3, this, (TInt) KMMCErrHardware ); sl@0: return KMMCErrHardware; sl@0: } sl@0: sl@0: SMF_STATE(EStCIDCmd) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM20, "EStCIDCmd" ); sl@0: s.FillCommandDesc(ECmdAllSendCID,0); sl@0: m.ResetTraps(); sl@0: SMF_INVOKES(ExecCommandSMST,EStSendCIDIssued) sl@0: sl@0: SMF_STATE(EStSendCIDIssued) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM21, "EStSendCIDIssued" ); sl@0: // All done - Higher level state machine expects CID in s.ResponseP() sl@0: sl@0: SMF_END sl@0: } sl@0: sl@0: TMMCErr DSDStack::ConfigureMemoryCardSMST(TAny* aStackP) sl@0: { return static_cast(aStackP)->ConfigureMemoryCardSM(); } sl@0: sl@0: TMMCErr DSDStack::ConfigureMemoryCardSM() sl@0: /** sl@0: */ sl@0: { sl@0: enum states sl@0: { sl@0: EStBegin=0, sl@0: EStSendCSDDone, sl@0: EStEnd sl@0: }; sl@0: sl@0: DMMCSession& s=Session(); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM, "Current session = 0x%x", &s ); sl@0: sl@0: //coverity[UNREACHABLE] sl@0: //Part of state machine design. sl@0: SMF_BEGIN sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM1, "EStBegin" ); sl@0: // Cards is initialised so get its CSD sl@0: sl@0: s.FillCommandDesc(ECmdSendCSD, TUint32(CardArray().CardP(iCxCardCount)->iRCA) << 16); sl@0: SMF_INVOKES(ExecCommandSMST, EStSendCSDDone) sl@0: sl@0: SMF_STATE(EStSendCSDDone) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM2, "EStSendCSDDone" ); sl@0: // Store the CSD in the new card entry sl@0: TMMCard* cardP = CardArray().CardP(iCxCardCount); sl@0: cardP->iCSD = s.ResponseP(); sl@0: sl@0: if(CardArray().Card(iCxCardCount).IsSDCard()) sl@0: { sl@0: // Perform SD Specific parsing of the CSD structure sl@0: if(cardP->CSD().CCC() & KMMCCmdClassLockCard) sl@0: { sl@0: cardP->iFlags |= KMMCardIsLockable; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // Perform MMC Specific parsing of the CSD structure sl@0: TUint specVers = cardP->CSD().SpecVers(); // 1 => 1.4, 2 => 2.0 - 2.2, 3 => 3.1 sl@0: if ((specVers >= 2) && (cardP->CSD().CCC() & KMMCCmdClassLockCard)) sl@0: { sl@0: cardP->iFlags |= KMMCardIsLockable; sl@0: } sl@0: } sl@0: sl@0: // Check the state of the mechanical write protect switch sl@0: if (WriteProtected(iCxCardCount)) sl@0: { sl@0: cardP->iFlags |= KMMCardIsWriteProtected; sl@0: } sl@0: sl@0: SMF_END sl@0: } sl@0: sl@0: EXPORT_C TMMCErr DSDStack::InitStackAfterUnlockSM() sl@0: // sl@0: // Performs initialisation of the SD card after the card has been unlocked sl@0: // sl@0: { sl@0: enum states sl@0: { sl@0: EStBegin=0, sl@0: EStNextCard, sl@0: EStSelectCard, sl@0: EStSetBusWidth, sl@0: EStSetBusWidth1, sl@0: EStGetSDStatus, sl@0: EStGetSDStatus1, sl@0: EStDecodeSDStatus, sl@0: EStDeselectCard, sl@0: EStCardDeselectedReadCSD, sl@0: EStCSDCmdSent, sl@0: EStMoreCardsCheck, sl@0: EStEnd sl@0: }; sl@0: sl@0: DMMCSession& s=Session(); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM, "Current session = 0x%x", &s ); sl@0: sl@0: SMF_BEGIN sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM1, "EStBegin" ); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf(">DSDStack::InitStackAfterUnlockSM()")); sl@0: iRCAPool.ReleaseUnlocked(); sl@0: iCxCardCount=0; // Reset current card number sl@0: sl@0: SMF_STATE(EStNextCard) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM2, "EStNextCard" ); sl@0: AddressCard(iCxCardCount); // Address the next card sl@0: sl@0: if (!CardDetect(iCxCardCount)) sl@0: SMF_GOTOS(EStMoreCardsCheck) sl@0: sl@0: s.SetCard(CardArray().CardP(iCxCardCount)); sl@0: sl@0: if (!CardArray().Card(iCxCardCount).IsSDCard()) sl@0: { sl@0: SMF_INVOKES( DMMCStack::InitCurrentCardAfterUnlockSMST, EStMoreCardsCheck ) sl@0: } sl@0: sl@0: SMF_STATE(EStSelectCard) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM3, "EStSelectCard" ); sl@0: TRCA targetRCA = CardArray().Card(iCxCardCount).RCA(); sl@0: if (targetRCA == SelectedCard()) sl@0: { sl@0: SMF_GOTOS(EStSetBusWidth) sl@0: } sl@0: sl@0: s.FillCommandDesc(ECmdSelectCard, targetRCA); sl@0: SMF_INVOKES(ExecCommandSMST,EStSetBusWidth) sl@0: sl@0: SMF_STATE(EStSetBusWidth) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM4, "EStSetBusWidth" ); sl@0: const TMMCStatus status = s.LastStatus(); sl@0: if((status & KMMCStatCardIsLocked) != 0) sl@0: SMF_GOTOS(EStDeselectCard) sl@0: sl@0: // set bus width with ACMD6 sl@0: TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16; sl@0: s.FillCommandDesc(ECmdAppCmd, arg); sl@0: SMF_INVOKES(IssueCommandCheckResponseSMST,EStSetBusWidth1) sl@0: sl@0: SMF_STATE(EStSetBusWidth1) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM5, "EStSetBusWidth1" ); sl@0: CardArray().Card(iCxCardCount).SetBusWidth(4); sl@0: DSDSession::FillAppCommandDesc(Command(), ESDACmdSetBusWidth, KSDBusWidth4); sl@0: SMF_INVOKES(IssueCommandCheckResponseSMST,EStGetSDStatus) sl@0: sl@0: SMF_STATE(EStGetSDStatus) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM6, "EStGetSDStatus" ); sl@0: // Now we have sent ACMD6, ask the controller to set the bus width to 4 sl@0: DoSetBusWidth(EBusWidth4); sl@0: sl@0: // get protected area size with ACMD13 sl@0: TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16; sl@0: s.FillCommandDesc(ECmdAppCmd,arg); sl@0: SMF_INVOKES(IssueCommandCheckResponseSMST,EStGetSDStatus1) sl@0: sl@0: SMF_STATE(EStGetSDStatus1) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM7, "EStGetSDStatus1" ); sl@0: DSDSession::FillAppCommandDesc(Command(), ESDACmdSDStatus); sl@0: s.FillCommandArgs(0, KSDStatusBlockLength, iPSLBuf, KSDStatusBlockLength); sl@0: SMF_INVOKES(IssueCommandCheckResponseSMST,EStDecodeSDStatus); sl@0: sl@0: SMF_STATE(EStDecodeSDStatus) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM8, "EStDecodeSDStatus" ); sl@0: #ifdef _DEBUG sl@0: for (TUint i = 0; i < KSDStatusBlockLength; ++i) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("SD_STATUS[0x%x] = %x", i, iPSLBuf[i])); sl@0: OstTraceExt2( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM9, "SD_STATUS[0x%x]=0x%x", i, (TUint) iPSLBuf[i]); sl@0: } sl@0: #endif sl@0: // bits 495:480 are SD_CARD_TYPE. Check this is 00xxh (x = don't care). sl@0: sl@0: if (iPSLBuf[2] != 0) sl@0: { sl@0: OstTraceFunctionExitExt( DSDSTACK_INITSTACKAFTERUNLOCKSM_EXIT, this, (TInt) KMMCErrNotSupported ); sl@0: return KMMCErrNotSupported; sl@0: } sl@0: sl@0: // bits 479:448 contain SIZE_OF_PROTECTED_AREA. sl@0: // (This is bytes 4 to 7 in big-endian format.) sl@0: sl@0: TSDCard& sdc = CardArray().Card(iCxCardCount); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Card %d", iCxCardCount)); sl@0: TUint32 size_of_protected_area = TMMC::BigEndian32(&iPSLBuf[4]); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: SizeOfProtectedArea: %d", size_of_protected_area)); sl@0: OstTraceExt2( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM10, "iCxCardCount=%d;SizeOfProtectedArea=%d", iCxCardCount, (TInt) size_of_protected_area); sl@0: const TCSD& csd = sdc.CSD(); sl@0: TUint32 pas = 0; sl@0: sl@0: if (sdc.IsHighCapacity()) sl@0: { sl@0: // High Capacity Card sl@0: // Protected Area = SIZE_OF_PROTECTED_AREA sl@0: pas = size_of_protected_area; sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack(SDHC): SetProtectedAreaSize: %d", pas)); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM11, "SDHC: SetProtectedAreaSize=%d", pas); sl@0: } sl@0: else sl@0: { sl@0: // Standard Capacity Card sl@0: // Protected Area = SIZE_OF_PROTECTED_AREA * C_SIZE_MULT * BLOCK_LEN sl@0: pas = size_of_protected_area * (1 << (csd.CSizeMult() + 2 + csd.ReadBlLen())); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack(SDSC): SetProtectedAreaSize: %d", pas)); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM12, "SDSC: SetProtectedAreaSize=%d", pas); sl@0: } sl@0: sl@0: sdc.SetProtectedAreaSize(pas); sl@0: sl@0: //bits 431:428 contain AU_SIZE sl@0: //(This is higher order 4 bits of 10th byte in big endian format) sl@0: TUint8 au = TUint8(iPSLBuf[10] >> 4); sl@0: if(au == 0) //AU_SIZE field in SD status register is undefined. sl@0: au = 6; //Defaulting to value corresponding to 512K sl@0: sdc.SetAUSize(au); sl@0: sl@0: SMF_INVOKES(SwitchToHighSpeedModeSMST, EStDeselectCard) sl@0: sl@0: SMF_STATE(EStDeselectCard) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM13, "EStDeselectCard" ); sl@0: s.FillCommandDesc(ECmdSelectCard, 0); sl@0: SMF_INVOKES(ExecCommandSMST, EStCardDeselectedReadCSD) sl@0: sl@0: SMF_STATE(EStCardDeselectedReadCSD) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM14, "EStCardDeselectedReadCSD" ); sl@0: // sl@0: // Read the card's CSD register (again) sl@0: // sl@0: // - We re-read the CSD, as the TRAN_SPEED field may have changed due to a switch to HS Mode sl@0: // sl@0: TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16; sl@0: s.FillCommandDesc( ECmdSendCSD, arg ); sl@0: SMF_INVOKES(ExecCommandSMST, EStCSDCmdSent) sl@0: sl@0: SMF_STATE(EStCSDCmdSent) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM15, "EStCSDCmdSent" ); sl@0: // sl@0: // Store the CSD in the card entry sl@0: // sl@0: TMMCard* cardP = iCardArray->CardP(iCxCardCount); sl@0: cardP->iCSD = s.ResponseP(); sl@0: sl@0: SMF_STATE(EStMoreCardsCheck) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM16, "EStMoreCardsCheck" ); sl@0: if (++iCxCardCount < (TInt)iMaxCardsInStack) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Address Next card: %d",iCxCardCount)); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM17, "Address Next card=%d", iCxCardCount); sl@0: SMF_GOTOS(EStNextCard) sl@0: } sl@0: else sl@0: { sl@0: AddressCard(KBroadcastToAllCards); sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("(aStackP)->DMMCStack::CIMReadWriteBlocksSM() ); } sl@0: sl@0: sl@0: EXPORT_C TMMCErr DSDStack::CIMReadWriteBlocksSM() sl@0: // sl@0: // This macro performs single/multiple block reads and writes sl@0: // For normal read/write block operations, this function determines the appropriate sl@0: // MMC command to send and fills the command descriptor accordingly based on sl@0: // the value of the session ID set. However, it is necessary to have set the sl@0: // command arguments (with DMMCSession::FillCommandArgs()) before this function sl@0: // is called. sl@0: // For special block read/write operations, e.g. lock/unlock, it is required to sl@0: // have already filled the command descriptor (with DMMCSession::FillCommandDesc()) sl@0: // for the special command required - in addition to have setup the command arguments. sl@0: // sl@0: { sl@0: enum states sl@0: { sl@0: EStBegin=0, sl@0: EStRestart, sl@0: EStAttached, sl@0: EStLength1, sl@0: EStLengthSet, sl@0: EStIssued, sl@0: EStWaitFinish, sl@0: EStWaitFinish1, sl@0: EStRWFinish, sl@0: EStDone, sl@0: EStEnd sl@0: }; sl@0: sl@0: DMMCSession& s = Session(); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM, "Current session = 0x%x", &s ); sl@0: sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:RWBlocksSM %x",TUint(s.iLastStatus))); sl@0: sl@0: SMF_BEGIN sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM1, "EStBegin" ); sl@0: TSDCard& sdCard = *static_cast(s.iCardP); sl@0: AddressCard(sdCard.iIndex-1); sl@0: sl@0: if(sdCard.IsSDCard() == EFalse) sl@0: { sl@0: // sl@0: // If this is not an SD card, then use the more appropriate sl@0: // MMC state machine as this is optimised for MMC performance sl@0: // sl@0: SMF_INVOKES(CIMReadWriteMemoryBlocksSMST, EStDone); sl@0: } sl@0: sl@0: if(s.iSessionID == ECIMWriteBlock || s.iSessionID == ECIMWriteMBlock) sl@0: { sl@0: // Check that the card supports class 4 (Write) commands sl@0: const TUint ccc = s.iCardP->CSD().CCC(); sl@0: if(!(ccc & KMMCCmdClassBlockWrite)) sl@0: { sl@0: OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT, this, (TInt) KMMCErrNotSupported ); sl@0: return KMMCErrNotSupported; sl@0: } sl@0: } sl@0: sl@0: Command().iCustomRetries = 0; // MBW retries sl@0: s.iState |= KMMCSessStateInProgress; sl@0: m.SetTraps(KMMCErrInitContext); sl@0: sl@0: SMF_STATE(EStRestart) // NB: ErrBypass is not processed here sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM2, "EStRestart" ); sl@0: SMF_CALLMEWR(EStRestart) // Create a recursive call entry to recover from the errors trapped sl@0: m.SetTraps(KMMCErrStatus); sl@0: if (s.Command().iSpec.iCommandClass!=KMMCCmdClassApplication || s.Command().iCommand==ECmdAppCmd ) sl@0: { sl@0: s.ResetCommandStack(); sl@0: SMF_INVOKES( AttachCardSMST, EStAttached ) // attachment is mandatory here sl@0: } sl@0: sl@0: SMF_BPOINT(EStAttached) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM3, "EStAttached" ); sl@0: TMMCCommandDesc& cmd = s.Command(); sl@0: sl@0: const TUint32 blockLength = cmd.BlockLength(); sl@0: if((blockLength == 0) || (blockLength > (TUint)KDefaultBlockLenInBytes)) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:RWBlocksSM err BlockLen:%d",blockLength)); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM4, "blockLength=%d", blockLength ); sl@0: OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT1, this, (TInt) KMMCErrArgument ); sl@0: return KMMCErrArgument; sl@0: } sl@0: sl@0: if(s.iSessionID == ECIMReadBlock || sl@0: s.iSessionID == ECIMWriteBlock || sl@0: s.iSessionID == ECIMReadMBlock || sl@0: s.iSessionID == ECIMWriteMBlock) sl@0: { sl@0: // read/write operation sl@0: if(!cmd.AdjustForBlockOrByteAccess(s)) sl@0: { sl@0: // unable to convert command arguments to suit the underlying block/byte access mode sl@0: OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT2, this, (TInt) KMMCErrArgument ); sl@0: return KMMCErrArgument; sl@0: } sl@0: } sl@0: sl@0: // Set the block length if it has changed. Always set for ECIMLockUnlock. sl@0: if ((blockLength == s.iCardP->iSetBlockLen) && (s.iSessionID != ECIMLockUnlock)) sl@0: { sl@0: SMF_GOTOS( EStLengthSet ) sl@0: } sl@0: sl@0: s.iCardP->iSetBlockLen = 0; sl@0: s.PushCommandStack(); sl@0: s.FillCommandDesc( ECmdSetBlockLen, blockLength ); sl@0: SMF_INVOKES( ExecCommandSMST, EStLength1 ) sl@0: sl@0: SMF_STATE(EStLength1) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM5, "EStLength1" ); sl@0: const TMMCStatus status(s.ResponseP()); sl@0: s.PopCommandStack(); sl@0: if (status.Error()) sl@0: { sl@0: OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT3, this, (TInt) KMMCErrStatus ); sl@0: SMF_RETURN(KMMCErrStatus) sl@0: } sl@0: s.iCardP->iSetBlockLen = s.Command().BlockLength(); sl@0: sl@0: SMF_STATE(EStLengthSet) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM6, "EStLengthSet" ); sl@0: TMMCCommandDesc& cmd = s.Command(); sl@0: TUint opType = 0; sl@0: const TUint kTypeWrite = KBit0; sl@0: const TUint kTypeMultiple = KBit1; sl@0: const TUint kTypeSpecial = KBit2; sl@0: static const TMMCCommandEnum cmdCodes[4] = sl@0: {ECmdReadSingleBlock, ECmdWriteBlock, ECmdReadMultipleBlock, ECmdWriteMultipleBlock}; sl@0: sl@0: switch( s.iSessionID ) sl@0: { sl@0: case ECIMReadBlock: sl@0: break; sl@0: case ECIMWriteBlock: sl@0: opType=kTypeWrite; sl@0: break; sl@0: case ECIMReadMBlock: sl@0: opType=kTypeMultiple; sl@0: break; sl@0: case ECIMWriteMBlock: sl@0: opType=kTypeWrite|kTypeMultiple; sl@0: break; sl@0: case ECIMLockUnlock: sl@0: default: sl@0: opType=kTypeSpecial; sl@0: break; sl@0: } sl@0: sl@0: const TUint blocks = cmd.iTotalLength / cmd.BlockLength(); sl@0: if ( blocks * cmd.BlockLength() != cmd.iTotalLength ) sl@0: { sl@0: OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT4, this, (TInt) KMMCErrArgument ); sl@0: return KMMCErrArgument; sl@0: } sl@0: sl@0: if ( !(opType & kTypeSpecial) ) // A special session has already set its command descriptor sl@0: { sl@0: if (blocks==1) sl@0: opType &= ~kTypeMultiple; sl@0: sl@0: TUint32 oldFlags = cmd.iFlags; // Store the existing command flags, as they will be reset by FillCommandDesc() sl@0: cmd.iCommand = cmdCodes[opType]; sl@0: s.FillCommandDesc(); sl@0: cmd.iFlags = oldFlags; // ...and restore the old command flags sl@0: } sl@0: sl@0: // NB We need to trap KMMCErrStatus errors, because if one occurs, sl@0: // we still need to wait to exit PRG/RCV/DATA state sl@0: if (Command().iCommand == ECmdWriteMultipleBlock) sl@0: { sl@0: Command().iExecNotHandle = KMMCErrDataCRC | KMMCErrDataTimeOut; sl@0: m.SetTraps(KMMCErrStatus | KMMCErrDataCRC | KMMCErrDataTimeOut); sl@0: } sl@0: else sl@0: { sl@0: m.SetTraps(KMMCErrStatus); sl@0: } sl@0: sl@0: SMF_INVOKES( ExecCommandSMST, EStIssued ) sl@0: sl@0: SMF_STATE(EStIssued) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM7, "EStIssued" ); sl@0: // check state of card after data transfer with CMD13. sl@0: if (s.Command().Direction() != 0) sl@0: { sl@0: SMF_GOTOS(EStWaitFinish) sl@0: } sl@0: sl@0: SMF_GOTOS(EStRWFinish); sl@0: sl@0: SMF_STATE(EStWaitFinish) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM8, "EStWaitFinish" ); sl@0: // if MBW fail, then recover by rewriting ALL blocks... sl@0: // (used to recover using ACMD22, but this has been changed sl@0: // as is difficult to test for little gain in efficiency) sl@0: if (Command().iCommand == ECmdWriteMultipleBlock && err != 0) sl@0: { sl@0: if (Command().iCustomRetries++ >= (TInt) KSDMaxMBWRetries) sl@0: { sl@0: OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT5, this, (TInt) err ); sl@0: SMF_RETURN(err) sl@0: } sl@0: sl@0: m.Pop(); // remove recursive call to EStRestart sl@0: SMF_GOTOS(EStRestart) sl@0: } sl@0: sl@0: // Save the status and examine it after issuing CMD13... sl@0: // NB We don't know where in the command stack the last response is stored (e.g. there may sl@0: // have bee a Deselect/Select issued), but we do know last response is stored in iLastStatus sl@0: TMMC::BigEndian4Bytes(s.ResponseP(), s.iLastStatus); sl@0: sl@0: // ...else issue CMD13 to poll for the card finishing and check for errors sl@0: s.PushCommandStack(); sl@0: s.FillCommandDesc(ECmdSendStatus, 0); sl@0: SMF_INVOKES(ExecCommandSMST, EStWaitFinish1) sl@0: sl@0: SMF_STATE(EStWaitFinish1) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM9, "EStWaitFinish1" ); sl@0: const TMMCStatus status(s.ResponseP()); sl@0: s.PopCommandStack(); sl@0: sl@0: #ifdef __WINS__ sl@0: SMF_GOTOS(EStRWFinish); sl@0: #else sl@0: const TMMCardStateEnum st1 = status.State(); sl@0: sl@0: if (st1 == ECardStatePrg || st1 == ECardStateRcv || st1 == ECardStateData) sl@0: { sl@0: SMF_INVOKES(ProgramTimerSMST, EStWaitFinish); sl@0: } sl@0: sl@0: if (status.Error()) sl@0: { sl@0: OstTraceFunctionExitExt( DUP7_DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT, this, (TInt) KMMCErrStatus ); sl@0: SMF_RETURN(KMMCErrStatus) sl@0: } sl@0: #endif sl@0: sl@0: // Fall through if CURRENT_STATE is not PGM or DATA sl@0: SMF_STATE(EStRWFinish) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM10, "EStRWFinish" ); sl@0: if (TMMCStatus(s.ResponseP()).Error() != 0) sl@0: { sl@0: OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT6, this, (TInt) KMMCErrStatus ); sl@0: SMF_RETURN(KMMCErrStatus); sl@0: } sl@0: sl@0: s.iState &= ~KMMCSessStateInProgress; sl@0: sl@0: // skip over recursive entry or throw error and catch in CIMLockUnlockSM() sl@0: TMMCErr ret = (s.Command().iCommand == ECmdLockUnlock) ? KMMCErrUpdPswd : KMMCErrBypass; sl@0: OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT7, this, (TInt) ret ); sl@0: return ret; sl@0: sl@0: SMF_STATE(EStDone) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM11, "EStDone" ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("(aStackP)->DSDStack::SwitchToHighSpeedModeSM() ); } sl@0: sl@0: TMMCErr DSDStack::SwitchToHighSpeedModeSM() sl@0: { sl@0: enum states sl@0: { sl@0: EStBegin=0, sl@0: EstCheckController, sl@0: EStSendSCRCmd, sl@0: EStCheckSpecVer, sl@0: EStCheckFunction, sl@0: EStCheckFunctionSent, sl@0: EStSwitchFunctionSent, sl@0: EStDone, sl@0: EStEnd sl@0: }; sl@0: sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:SwitchToHighSpeedModeSM ")); sl@0: sl@0: DMMCSession& s = Session(); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM, "Current session = 0x%x", &s ); sl@0: sl@0: SMF_BEGIN sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM1, "EStBegin"); sl@0: sl@0: SMF_STATE(EstCheckController) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM2, "EstCheckController"); sl@0: // Get the clock speed supported by the controller sl@0: TMMCMachineInfoV4 machineInfo; sl@0: TMMCMachineInfoV4Pckg machineInfoPckg(machineInfo); sl@0: MachineInfo(machineInfoPckg); sl@0: sl@0: if (machineInfo.iVersion >= TMMCMachineInfoV4::EVersion4) sl@0: { sl@0: if (machineInfo.iMaxClockSpeedInMhz < (KSDDTClk50MHz/1000) ) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf("High speed mode not supported by controller")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM3, "High speed mode not supported by controller"); sl@0: SMF_GOTOS(EStDone); sl@0: } sl@0: } sl@0: sl@0: SMF_STATE(EStSendSCRCmd) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM4, "EStSendSCRCmd"); sl@0: // sl@0: // ACMD51 Read the SD Configuration Register sl@0: // sl@0: DSDSession::FillAppCommandDesc(Command(), ESDACmdSendSCR); sl@0: s.FillCommandArgs(0, KSDSCRLength, iPSLBuf, KSDSCRLength); sl@0: SMF_INVOKES(ExecCommandSMST, EStCheckSpecVer); sl@0: sl@0: SMF_STATE(EStCheckSpecVer) sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM5, "EStCheckSpecVer"); sl@0: // sl@0: // Check the SD version sl@0: // sl@0: // 0 : version 1.0-1.01 : SDHS Is NOT Supported sl@0: // 1 : version 1.10+ : SDHS Is Supported sl@0: // sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" SD Configuration Register received")); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" ...card_status=%x", TUint(s.iLastStatus))); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM6, "SD Configuration Register received: card_status=0x%x", (TUint) s.iLastStatus); sl@0: sl@0: #ifdef _DEBUG sl@0: for (TUint32 i = 0; i < KSDSCRLength; ++i) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SCR_STATUS[0x%x] = %x", i, iPSLBuf[i])); sl@0: } sl@0: #endif sl@0: sl@0: if(iPSLBuf[0]==2) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 2")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM7, "SD Spec Version 2"); sl@0: SMF_GOTOS(EStCheckFunction); sl@0: } sl@0: sl@0: if(iPSLBuf[0]==1) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 1.10")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM8, "SD Spec Version 1.10"); sl@0: SMF_GOTOS(EStCheckFunction); sl@0: } sl@0: sl@0: if(iPSLBuf[0]==0) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 1.01")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM9, "SD Spec Version 1.01"); sl@0: SMF_GOTOS(EStDone); sl@0: } sl@0: sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version > 2 !")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM10, "SD Spec Version > 2"); sl@0: sl@0: SMF_STATE(EStCheckFunction) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM11, "EStCheckFunction"); sl@0: m.SetTraps(KMMCErrResponseTimeOut | KMMCErrNotSupported); sl@0: sl@0: // sl@0: // SD1.1 uses CMD6 which is not defined by the MMCA sl@0: // - fill in command details using the SD Specific command description table sl@0: // sl@0: sl@0: DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSwitchFunction); sl@0: s.FillCommandArgs(KSDCheckFunctionHighSpeed, KSDSwitchFuncLength, iPSLBuf, KSDSwitchFuncLength); sl@0: sl@0: SMF_INVOKES(IssueCommandCheckResponseSMST,EStCheckFunctionSent) sl@0: sl@0: SMF_STATE(EStCheckFunctionSent) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM12, "EStCheckFunctionSent"); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" CheckFunctionSent %x",TUint(s.iLastStatus))); sl@0: OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM13, "CheckFunctionSent=0x%x", (TUint) s.iLastStatus); sl@0: sl@0: m.ResetTraps(); sl@0: sl@0: if(err == KMMCErrResponseTimeOut) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Read] Response Timeout")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM14, "CMD6 [Read] Response Timeout"); sl@0: SMF_GOTOS(EStDone); sl@0: } sl@0: else if(err == KMMCErrNotSupported) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Read] Not Supported")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM15, "CMD6 [Read] Not Supported"); sl@0: SMF_GOTOS(EStDone); sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: for (TUint32 i = 0; i < KSDSwitchFuncLength; ++i) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SD Switch Func Status[0x%x] = %x", i, iPSLBuf[i])); sl@0: } sl@0: sl@0: m.SetTraps(KMMCErrResponseTimeOut); sl@0: #endif sl@0: sl@0: // sl@0: // SD1.1 uses CMD6 which is not defined by the MMCA sl@0: // - fill in command details using the SD Specific command description table sl@0: // sl@0: sl@0: DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSwitchFunction); sl@0: s.FillCommandArgs(KSDSwitchFunctionHighSpeed, KSDSwitchFuncLength, iPSLBuf, KSDSwitchFuncLength); sl@0: sl@0: SMF_INVOKES(IssueCommandCheckResponseSMST,EStSwitchFunctionSent) sl@0: sl@0: SMF_STATE(EStSwitchFunctionSent) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM16, "EStSwitchFunctionSent"); sl@0: #ifdef _DEBUG sl@0: m.ResetTraps(); sl@0: sl@0: if(err == KMMCErrResponseTimeOut) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Write] Response Timeout")); sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM17, "CMD6 [Write] Response Timeout"); sl@0: } sl@0: sl@0: for (TUint32 i = 0; i < KSDSwitchFuncLength; ++i) sl@0: { sl@0: __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SD Switch[0x%x] = %x", i, iPSLBuf[i])); sl@0: OstTraceExt2( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM18, "SD Switch[0x%x]=0x%x", (TUint) i, (TUint) iPSLBuf[i]); sl@0: } sl@0: #endif sl@0: sl@0: SMF_STATE(EStDone) sl@0: sl@0: OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM19, "EStSwitchFunctionSent"); sl@0: sl@0: SMF_END sl@0: } sl@0: sl@0: sl@0: EXPORT_C DMMCSession* DSDStack::AllocSession(const TMMCCallBack& aCallBack) const sl@0: /** sl@0: * Factory function to create DMMCSession derived object. Non-generic MMC sl@0: * controllers can override this to generate more specific objects. sl@0: * @param aCallBack Callback function to notify the client that a session has completed sl@0: * @return A pointer to the new session sl@0: */ sl@0: { sl@0: OstTraceFunctionEntry1( DSDSTACK_ALLOCSESSION_ENTRY, this ); sl@0: return new DSDSession(aCallBack); sl@0: } sl@0: sl@0: EXPORT_C void DSDStack::Dummy1() {} sl@0: EXPORT_C void DSDStack::Dummy2() {} sl@0: EXPORT_C void DSDStack::Dummy3() {} sl@0: EXPORT_C void DSDStack::Dummy4() {}