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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include <drivers/sdcard.h>
17 #include "OstTraceDefinitions.h"
18 #ifdef OST_TRACE_COMPILER_IN_USE
19 #include "locmedia_ost.h"
21 #pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
23 #include "sdcardTraces.h"
27 // ======== TSDCard ========
30 : iProtectedAreaSize(0), iPARootDirEnd(KPARootDirEndUnknown)
35 TInt64 TSDCard::DeviceSize64() const
37 // returns the SD device size
40 OstTraceFunctionEntry1( TSDCARD_DEVICESIZE64_ENTRY, this );
41 if(iFlags & KSDCardIsSDCard)
43 return (IsHighCapacity()) ? 512 * 1024 * (TInt64)(1 + CSD().CSDField(69, 48)) : TMMCard::DeviceSize64();
46 return(TMMCard::DeviceSize64());
49 TUint32 TSDCard::PreferredWriteGroupLength() const
51 // return SD erase sector size, (SECTOR_SIZE + 1) * 2 ** WRITE_BLK_LEN
54 OstTraceFunctionEntry1( TSDCARD_PREFERREDWRITEGROUPLENGTH_ENTRY, this );
55 if(iFlags & KSDCardIsSDCard)
58 return (sdcsd.SDSectorSize() + 1) * (1 << sdcsd.WriteBlLen());
61 return(TMMCard::PreferredWriteGroupLength());
64 TInt TSDCard::GetFormatInfo(TLDFormatInfo& /*aFormatInfo*/) const
66 return KErrNotSupported;
69 TUint32 TSDCard::MinEraseSectorSize() const
71 if(iFlags&KSDCardIsSDCard)
74 if (sdcsd.SDEraseBlkEn())
75 return sdcsd.WriteBlockLength(); // raised logarithm
77 return (sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength();
80 return TMMCard::MinEraseSectorSize();
84 const TUint32 KEraseSectorSizeShift = 8; // KEraseSectorSizeShift determines the multiple of the sector size
85 // that can be erased in one operation
86 TUint32 TSDCard::EraseSectorSize() const
88 if(iFlags&KSDCardIsSDCard)
91 return ((sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength()) << KEraseSectorSizeShift;
94 return TMMCard::EraseSectorSize();
97 const TInt KDefaultBlockLen = 9; // 2^9 = 512 bytes
98 const TInt KDefaultBlockLenInBytes = 1 << KDefaultBlockLen; // 2^9 = 512 bytes
99 const TInt KTwoGbyteSDBlockLen = 10; // 2^10 = 1024 bytes
100 const TInt KFourGbyteSDBlockLen = 11; // 2^11 = 2048 bytes
102 TInt TSDCard::GetEraseInfo(TMMCEraseInfo& aEraseInfo) const
104 // Return info. on erase services for this card
107 OstTraceFunctionEntry1( TSDCARD_GETERASEINFO_ENTRY, this );
109 // SD Controllers support MMC cards too. Check if we are really dealing with an SD card
110 if(!(iFlags&KSDCardIsSDCard))
111 return(TMMCard::GetEraseInfo(aEraseInfo));
113 if (CSD().CCC() & KMMCCmdClassErase)
115 // This card supports erase cmds. However, SD cards don't support Erase Group commands (i.e. CMD35, CMD36).
116 OstTrace0( TRACE_INTERNALS, TSDCARD_GETERASEINFO, "Card supports erase class commands" );
117 aEraseInfo.iEraseFlags=KMMCEraseClassCmdsSupported;
119 // Return the preferred size to be used as the unit for erase operations.
121 TUint32 prefSize=((sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength());
122 prefSize<<=KEraseSectorSizeShift; // Use multiples of the sector size for each erase operation
123 aEraseInfo.iPreferredEraseUnitSize=prefSize;
125 // Return the smallest size that can be used as the unit for erase operations
126 if (sdcsd.SDEraseBlkEn())
128 aEraseInfo.iMinEraseSectorSize = KDefaultBlockLenInBytes;
132 aEraseInfo.iMinEraseSectorSize=(sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength();
136 aEraseInfo.iEraseFlags=0;
138 OstTraceFunctionExitExt( TSDCARD_GETERASEINFO_EXIT, this, KErrNone );
142 TInt TSDCard::MaxReadBlLen() const
144 * Returns the maximum read block length supported by the card encoded as a logarithm
145 * Normally this is the same as the READ_BL_LEN field in the CSD register,
146 * but for high capacity cards (> 2GB) this is set to a maximum of 512 bytes,
147 * if possible, to try to avoid compatibility issues.
150 OstTraceFunctionEntry1( TSDCARD_MAXREADBLLEN_ENTRY, this );
153 TInt blkLenLog2 = CSD().ReadBlLen();
154 if (blkLenLog2 == KTwoGbyteSDBlockLen || blkLenLog2 == KFourGbyteSDBlockLen)
156 // The SD card spec. makes a special case for 2GByte cards,
157 // ...and some manufacturers apply the same method to support 4G cards
158 __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl > 2GB SD"));
159 OstTrace0( TRACE_INTERNALS, TSDCARD_MAXREADBLLEN, "SD Card > 2GB" );
160 blkLenLog2 = KDefaultBlockLen;
162 OstTraceFunctionExitExt( TSDCARD_MAXREADBLLEN_EXIT, this, blkLenLog2 );
167 TInt ret = TMMCard::MaxReadBlLen();
168 OstTraceFunctionExitExt( DUP1_TSDCARD_MAXREADBLLEN_EXIT, this, ret );
173 TInt TSDCard::MaxWriteBlLen() const
175 * Returns the maximum write block length supported by the card encoded as a logarithm
176 * Normally this is the same as the WRITE_BL_LEN field in the CSD register,
177 * but for high capacity cards (> 2GB) this is set to a maximum of 512 bytes,
178 * if possible, to try to avoid compatibility issues.
181 OstTraceFunctionEntry1( TSDCARD_MAXWRITEBLLEN_ENTRY, this );
184 TInt blkLenLog2 = CSD().WriteBlLen();
185 if (blkLenLog2 == KTwoGbyteSDBlockLen || blkLenLog2 == KFourGbyteSDBlockLen)
187 // The SD card spec. makes a special case for 2GByte cards,
188 // ...and some manufacturers apply the same method to support 4G cards
189 __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mwbl > 2GB SD"));
190 OstTrace0( TRACE_INTERNALS, TSDCARD_MAXWRITEBLLEN, "SD Card > 2GB" );
191 blkLenLog2 = KDefaultBlockLen;
193 OstTraceFunctionExitExt( TSDCARD_MAXWRITEBLLEN_EXIT, this, blkLenLog2 );
198 TInt ret = TMMCard::MaxWriteBlLen();
199 OstTraceFunctionExitExt( DUP1_TSDCARD_MAXWRITEBLLEN_EXIT, this, ret );
204 TUint TSDCard::MaxTranSpeedInKilohertz() const
206 * Returns the maximum supported clock rate for the card, in Kilohertz.
207 * @return Speed, in Kilohertz
210 OstTraceFunctionEntry1( TSDCARD_MAXTRANSPEEDINKILOHERTZ_ENTRY, this );
211 TUint maxClk = TMMCard::MaxTranSpeedInKilohertz();
215 __KTRACE_OPT(KPBUS1, Kern::Printf("\t >TSDCard(%d): MaxTranSpeedInKilohertz: %d",(iIndex-1),maxClk));
218 //MaxClk for SD should only be either 25000KHz or 50000KHz
219 if ( (maxClk != KSDDTClk25MHz) && (maxClk != KSDDTClk50MHz) )
221 __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Non-Compliant DT Clock"));
222 OstTrace0( TRACE_INTERNALS, TSDCARD_MAXTRANSPEEDINKILOHERTZ, "Non-Compliant DT Clock" );
225 if (maxClk > KSDDTClk50MHz)
227 //Clock rate exceeds SD possible max clock rate
228 __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Tuning DT Clock down to 50MHz"));
229 OstTrace0( TRACE_INTERNALS, TSDCARD_MAXTRANSPEEDINKILOHERTZ1, "Tuning DT Clock down to 50MHz" );
230 maxClk = KSDDTClk50MHz;
234 OstTraceFunctionExitExt( TSDCARD_MAXTRANSPEEDINKILOHERTZ_EXIT, this, maxClk );
238 // ======== TSDCardArray ========
240 EXPORT_C TInt TSDCardArray::AllocCards()
242 // allocate TSDCard objects for iCards and iNewCardsArray. This function
243 // is called at bootup as part of stack allocation so there is no cleanup
247 OstTraceFunctionEntry1( TSDCARDARRAY_ALLOCCARDS_ENTRY, this );
248 for (TInt i = 0; i < (TInt) KMaxMMCardsPerStack; ++i)
250 // zeroing the card data used to be implicit because embedded in
251 // CBase-derived DMMCStack.
252 if ((iCards[i] = new TSDCard) == 0)
254 OstTraceFunctionExitExt( TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNoMemory );
257 iCards[i]->iUsingSessionP = 0;
258 if ((iNewCards[i] = new TSDCard) == 0)
260 OstTraceFunctionExitExt( DUP1_TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNoMemory );
265 OstTraceFunctionExitExt( DUP2_TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNone );
269 void TSDCardArray::AddCardSDMode(TUint aCardNumber,const TUint8* aCID,TRCA* aNewRCA)
271 // Add an MMC card straight to the main card array in slot 'aCardNumber'. Save
272 // the CID value in the slot. Return a RCA for the card.
275 OstTraceFunctionEntryExt( TSDCARDARRAY_ADDCARDSDMODE_ENTRY, this );
279 // First, lets check if the same card was here before. If it was, keep the same RCA
280 if (Card(aCardNumber).IsPresent() && Card(aCardNumber).iCID==aCID)
281 rca=Card(aCardNumber).iRCA;
284 // Allocate and new RCA and store the CID in the slot selected
285 __ASSERT_ALWAYS( (rca=iOwningStack->iRCAPool.GetFreeRCA())!=0,DMMCSocket::Panic(DMMCSocket::EMMCNoFreeRCA) );
286 Card(aCardNumber).iCID=aCID;
287 if ( Card(aCardNumber).iRCA != 0 )
288 iOwningStack->iRCAPool.UnlockRCA(Card(aCardNumber).iRCA);
289 Card(aCardNumber).iRCA=rca;
290 iOwningStack->iRCAPool.LockRCA(Card(aCardNumber).iRCA);
293 Card(aCardNumber).iIndex=(aCardNumber+1); // Mark card as being present
295 OstTraceFunctionExit1( TSDCARDARRAY_ADDCARDSDMODE_EXIT, this );
298 TInt TSDCardArray::StoreRCAIfUnique(TUint aCardNumber,TRCA& anRCA)
300 // Check that no other array element has the same RCA value 'anRCA'. If no
301 // no duplication then store in slot 'aCardNumber'.
304 OstTraceExt3(TRACE_FLOW, TSDCARDARRAY_STORERCAIFUNIQUE_ENTRY ,"TSDCardArray::StoreRCAIfUnique;aCardNumber=%x;anRCA=%x;this=%x", aCardNumber, (TUint) anRCA, (TUint) this);
308 OstTraceFunctionExitExt( TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrGeneral );
311 Card(aCardNumber).iRCA=0;
313 // Now let's look if we've seen this card before
314 for ( TUint i=0 ; i<iOwningStack->iMaxCardsInStack ; i++ )
316 if ( Card(i).IsPresent() && Card(i).iRCA==anRCA )
318 OstTraceFunctionExitExt( DUP1_TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrInUse );
322 Card(aCardNumber).iRCA=anRCA;
323 Card(aCardNumber).iIndex=(aCardNumber+1); // Mark card as being present
324 OstTraceFunctionExitExt( DUP2_TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrNone );
328 EXPORT_C void TSDCardArray::DeclareCardAsGone(TUint aCardNumber)
330 // reset SD specific fields to initial values and then reset generic MultiMediaCard
333 OstTraceFunctionEntryExt( TSDCARDARRAY_DECLARECARDASGONE_ENTRY, this );
334 Card(aCardNumber).SetBusWidth(1);
335 TMMCardArray::DeclareCardAsGone(aCardNumber);
336 OstTraceFunctionExit1( TSDCARDARRAY_DECLARECARDASGONE_EXIT, this );
339 // ======== DSDSession ========
341 void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc, TSDAppCmd aCmd)
343 OstTraceFunctionEntry0( DSDSESSION_FILLAPPCOMMANDDESC_ENTRY );
344 aDesc.iCommand = (TMMCCommandEnum) aCmd;
345 aDesc.iArgument = 0; // set stuff bits to zero
346 FillAppCommandDesc(aDesc);
347 OstTraceFunctionExit0( DSDSESSION_FILLAPPCOMMANDDESC_EXIT );
350 void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc, TSDAppCmd aCmd, TMMCArgument aArg)
352 OstTraceFunctionEntry0( DUP1_DSDSESSION_FILLAPPCOMMANDDESC_ENTRY );
353 aDesc.iCommand = (TMMCCommandEnum) aCmd;
354 aDesc.iArgument = aArg;
355 FillAppCommandDesc(aDesc);
356 OstTraceFunctionExit0( DUP1_DSDSESSION_FILLAPPCOMMANDDESC_EXIT );
359 const TUint32 CCA = KMMCCmdClassApplication;
360 const TMMCIdxCommandSpec AppCmdSpecTable[] =
361 { // Class Type Dir MBlk StopT Rsp Type Len
362 {ESDACmdSetBusWidth, {CCA,ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD6
363 {ESDACmdSDStatus, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD13
364 {ESDACmdSendNumWrBlocks, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD22
365 {ESDACmdSetWrBlkEraseCount, {CCA,ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD23
366 {ESDACmdSDAppOpCond, {CCA,ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR3, 4}}, //ACMD41
367 {ESDACmdSetClrCardDetect, {CCA,ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD42
368 {ESDACmdSendSCR, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}} //ACMD51
371 void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc)
373 OstTraceFunctionEntry0( DUP2_DSDSESSION_FILLAPPCOMMANDDESC_ENTRY );
374 aDesc.iSpec = FindCommandSpec(AppCmdSpecTable, aDesc.iCommand);
376 aDesc.iBytesDone = 0;
377 OstTraceFunctionExit0( DUP2_DSDSESSION_FILLAPPCOMMANDDESC_EXIT );
380 const TMMCIdxCommandSpec SdSpecificCmdSpecTable[] =
382 * SD Specific Command Table
384 * - Some commands defined in the SD specification overload those defined in the MMC specification.
385 * This table contains the SD specific versions of those commands.
388 // Class Type Dir MBlk StopT Rsp Type Len
389 {ESDCmdSendRelativeAddress, {KMMCCmdClassBasic, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR6, 4}}, // CMD3 : SEND_RELATIVE_ADDRESS
390 {ESDCmdSwitchFunction, {KMMCCmdClassSwitch,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, // CMD6 : SWITCH_FUNCTION
391 {ESDCmdSendIfCond, {KMMCCmdClassBasic, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR7, 4}} // CMD8 : SEND_IF_COND
394 void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc, TSDSpecificCmd aCmd, TMMCArgument aArg)
396 OstTraceFunctionEntry0( DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY );
397 aDesc.iCommand = (TMMCCommandEnum) aCmd;
398 aDesc.iArgument = aArg;
399 FillSdSpecificCommandDesc(aDesc);
400 OstTraceFunctionExit0( DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT );
403 void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc, TSDSpecificCmd aCmd)
405 OstTraceFunctionEntry0( DUP1_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY );
406 aDesc.iCommand = (TMMCCommandEnum) aCmd;
407 aDesc.iArgument = 0; // set stuff bits to zero
408 FillSdSpecificCommandDesc(aDesc);
409 OstTraceFunctionExit0( DUP1_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT );
412 void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc)
414 OstTraceFunctionEntry0( DUP2_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY );
415 aDesc.iSpec = FindCommandSpec(SdSpecificCmdSpecTable, aDesc.iCommand);
417 aDesc.iBytesDone = 0;
418 OstTraceFunctionExit0( DUP2_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT );
422 // ======== DSDStack ========
424 EXPORT_C TInt DSDStack::Init()
426 OstTraceFunctionEntry1( DSDSTACK_INIT_ENTRY, this );
427 TInt ret = DMMCStack::Init();
428 OstTraceFunctionExitExt( DSDSTACK_INIT_EXIT, this, ret );
433 const TInt KMaxRCASendLoops=3;
434 const TUint KSDMaxPollAttempts=25;
435 EXPORT_C TMMCErr DSDStack::AcquireStackSM()
437 // This macro acquires new cards in an SD Card - star topology stack.
438 // This means each card has its own CMD and DAT lines and can be addressed
439 // individually by the Controller in turn. Commands can also be broadcast
440 // simultaneously to the entire stack.
441 // It starts with the Controller reading the operating conditions of each
442 // card in the stack (SEND_OP_COND - ACMD41). Then, the following
443 // initialisation sequence is performed to each card in turn:-
444 // New cards in the stack are identified (ALL_SEND_CID - CMD2) and each one
445 // is requested to publish a relative card address (SEND_RCA - CMD3). Finally,
446 // the card specific data (SEND_CSD - CMD9) is read from each card.
447 // Note that the initialization of MMC cards are supported by this function
448 // if they are encountered. These require a slightly different init. procdure.
463 DMMCSession& s=Session();
464 OstTrace1( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM, "Current session = 0x%x", &s );
468 OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM1, "EStBegin" );
469 __KTRACE_OPT(KPBUS1, Kern::Printf(">DSDStack::AcquireStackSM()"));
471 iRCAPool.ReleaseUnlocked();
472 iCxCardCount=0; // Reset current card number
474 SMF_STATE(EStNextFullRange)
476 OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM2, "EStNextFullRange" );
477 iCxCardType = ESDCardTypeUnknown;
479 AddressCard(iCxCardCount); // Address the next card
481 // Before issueing commands, see if there's actually a card present
482 if (!CardDetect(iCxCardCount))
483 SMF_GOTOS(EStMoreCardsCheck)
485 m.SetTraps(KMMCErrResponseTimeOut);
486 SMF_INVOKES(InitialiseMemoryCardSMST, EStSendCIDIssued)
488 SMF_STATE(EStSendCIDIssued)
490 OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM3, "EStSendCIDIssued" );
493 // The card responded with a CID. We need to initialise the
494 // appropriate entry in the card array with the CID.
495 if (iCxCardType==ESDCardTypeIsSD)
497 // Now prepare to recieve an RCA from to the card
498 CardArray().CardP(iCxCardCount)->iCID=s.ResponseP();
499 DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSendRelativeAddress,0); // SEND_RCA with argument just stuff bits
502 iCxPollRetryCount=0; // Init count of send RCA attempts
503 SMF_GOTOS(EStIssueSendRCA)
507 // The card array allocates an RCA, either the old RCA
508 // if we have seen this card before, or a new one.
510 CardArray().AddCardSDMode(iCxCardCount,s.ResponseP(),&rca);
512 // Now assign the new RCA to the card
513 s.FillCommandDesc(ECmdSetRelativeAddr,TMMCArgument(rca));
515 SMF_INVOKES(ExecCommandSMST,EStRCADone)
521 SMF_GOTOS(EStMoreCardsCheck) // Timed out, try the next card slot
524 SMF_STATE(EStIssueSendRCA)
526 OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM4, "EStIssueSendRCA" );
527 SMF_INVOKES(ExecCommandSMST,EStSendRCACheck)
529 SMF_STATE(EStSendRCACheck)
531 OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM5, "EStSendRCACheck" );
532 // We need to check that the RCA recieved from the card doesn't clash
533 // with any others in this stack. RCA is first 2 bytes of response buffer (in big endian)
534 TRCA rca=(TUint16)((s.ResponseP()[0]<<8) | s.ResponseP()[1]);
535 if (CardArray().StoreRCAIfUnique(iCxCardCount,rca)!=KErrNone)
536 SMF_GOTOS( ((++iCxPollRetryCount<KMaxRCASendLoops)?EStIssueSendRCA:EStMoreCardsCheck) )
538 SMF_STATE(EStRCADone)
540 OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM6, "EStRCADone" );
541 SMF_INVOKES(ConfigureMemoryCardSMST, EStMoreCardsCheck)
543 SMF_STATE(EStMoreCardsCheck)
545 OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM7, "EStMoreCardsCheck" );
546 if (++iCxCardCount < (TInt)iMaxCardsInStack)
548 __KTRACE_OPT(KPBUS1, Kern::Printf(">DSDStack::AcquireStackSM(): More Cards to check: %d",iCxCardCount));
549 OstTrace1( TRACE_INTERNALS, DSDSTACK_ACQUIRESTACKSM8, "More Cards to check: iCxCardCount=%d", iCxCardCount );
550 SMF_GOTOS(EStNextFullRange)
554 AddressCard(KBroadcastToAllCards); // Set back to broadcast mode
555 __KTRACE_OPT(KPBUS1, Kern::Printf("<DSDStack::AcquireStackSM()"));
562 TMMCErr DSDStack::InitialiseMemoryCardSMST(TAny* aStackP)
563 { return static_cast<DSDStack*>(aStackP)->InitialiseMemoryCardSM(); }
566 TMMCErr DSDStack::InitialiseMemoryCardSM()
573 EStSendInterfaceCondition,
574 EStSentInterfaceCondition,
576 EStCheckForFullRangeCmd41Timeout,
577 EStSentAppCommandBeforeCheckVoltage,
581 EStCheckForRangeCmd41Timeout,
582 EStSetRangeBusyCheck,
588 DMMCSession& s=Session();
589 DMMCPsu* psu=(DMMCPsu*)MMCSocket()->iVcc;
590 OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM, "Current session = 0x%x", &s );
592 static const TUint32 KCmd8Param = 0x0100 | 0x00AA; // Voltage supplied : 2.7-3.6V, Check Pattern 10101010b
593 static const TUint32 KCmd8CheckMask = 0x00000FFF;
597 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM1, "EStBegin" );
598 iCxCardType = ESDCardTypeUnknown;
599 s.iCardP = NULL; // This stops ExecCommandSM() from setting old RCA when sending CMD55
601 // Send CMD0 to initialise memory
602 SMF_INVOKES(GoIdleSMST, EStSendInterfaceCondition);
604 SMF_STATE(EStSendInterfaceCondition)
606 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM2, "EStSendInterfaceCondition" );
607 iCxPollRetryCount=0; // Reset max number of poll attempts on card busy
608 iConfig.SetPollAttempts(KSDMaxPollAttempts); // Increase card busy timeout to 1 Sec for SD Cards
610 iConfig.RemoveMode( KMMCModeEnableTimeOutRetry ); // Temporarily disable timeout retries - since we use a timeout event to distinguish between MMC and SD
612 DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSendIfCond, KCmd8Param);
614 // SD2.0 defines CMD8 as having a new response type - R7
615 // if the PSL doesn't indicate support for R7, use R1 instead
616 if (!(MMCSocket()->MachineInfo().iFlags & TMMCMachineInfo::ESupportsR7))
618 __KTRACE_OPT(KPBUS1, Kern::Printf("R7 not supported."));
619 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM3, "R7 not supported" );
620 Command().iSpec.iResponseType = ERespTypeR1;
624 m.SetTraps(KMMCErrAll);
625 SMF_INVOKES(ExecCommandSMST, EStSentInterfaceCondition)
627 SMF_STATE(EStSentInterfaceCondition)
629 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM4, "EStSentInterfaceCondition" );
630 if (err == KMMCErrNone)
632 // Check the response for voltage and check pattern
633 const TUint32 status = TMMC::BigEndian32(s.ResponseP());
634 if((status & KCmd8CheckMask) == KCmd8Param)
636 __KTRACE_OPT(KPBUS1, Kern::Printf("Found v2 card."));
637 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM5, "Found v2 card" );
638 iCurrentOpRange |= KMMCOCRAccessModeHCS;
642 // Pattern Mis-match, card does not support the specified voltage range
643 OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT, this, (TInt) KMMCErrNotSupported );
644 return KMMCErrNotSupported;
647 SMF_GOTOS(EStCheckVoltage);
650 // Go idle again after CMD8 failure
651 SMF_INVOKES(GoIdleSMST, EStCheckVoltage);
654 SMF_STATE(EStCheckVoltage)
656 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM6, "EStCheckVoltage" );
657 // If platform doesn't support an adjustable voltage PSU then there's no
658 // point in doing a full range for its supported range. To support range
659 // checking on a multi-card stack would require a complete scan of all
660 // cards before actually setting the range. This would over-complicate things
661 // and make the more normal single card/none adjustable cases less efficient.
662 if ( !(psu->VoltageSupported()&KMMCAdjustableOpVoltage) || iMaxCardsInStack>1)
664 // if the PSU isn't adjustable then it can't support low voltage mode
665 iCurrentOpRange&= ~KMMCOCRLowVoltage;
667 SMF_GOTOS(EStSetRangeCmd)
670 SMF_STATE(EStSetFullRangeCmd)
672 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM7, "EStSetFullRangeCmd" );
673 // Issue ACMD41/CMD1 with omitted voltage range
674 if (iCxCardType==ESDCardTypeIsMMC)
676 s.FillCommandDesc(ECmdSendOpCond, KMMCOCRAccessModeHCS | KMMCOCRBusy); // Full range + Sector Access + Busy bit (iArgument==KBit31)
677 SMF_NEXTS(EStFullRangeDone)
681 DSDSession::FillAppCommandDesc(Command(), ESDACmdSDAppOpCond, TMMCArgument(0));
682 SMF_NEXTS(EStCheckForFullRangeCmd41Timeout)
685 m.SetTraps(KMMCErrResponseTimeOut);
686 SMF_CALL(ExecCommandSMST)
688 SMF_STATE(EStCheckForFullRangeCmd41Timeout)
690 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM8, "EStCheckForFullRangeCmd41Timeout" );
691 if (err==KMMCErrResponseTimeOut)
693 __KTRACE_OPT(KPBUS1, Kern::Printf("ACMD 41 not supported - Assuming MMC"));
694 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM9, "ACMD 41 not supported - Assuming MMC" );
695 iCxCardType=ESDCardTypeIsMMC;
697 // Send CMD0 to re-initialise the card - otherwise we may get
698 // KMMCStatErrIllegalCommand returned for the next command
699 // expecting an R1 response. NB The SD spec recommends ignoring the error
700 // whereas the SDIO spec recommends this approach (ignoring the error
701 // would be difficult to code anyway, since by then we're no longer
702 // in this state machine).
703 SMF_INVOKES(GoIdleSMST, EStSetFullRangeCmd); // Repeat - but using CMD1
707 // No response timeout - so it must be an SD Card
708 (CardArray().CardP(iCxCardCount)->iFlags)|=KSDCardIsSDCard;
709 iCxCardType=ESDCardTypeIsSD;
712 SMF_STATE(EStFullRangeDone)
714 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM10, "EStFullRangeDone" );
717 // Card responded with Op range - evaluate the common subset with the current setting.
718 // Dont worry about the busy bit for now, we'll check that when we repeat the command
719 const TUint32 range = (iCurrentOpRange & ~KMMCOCRAccessModeHCS) & (TMMC::BigEndian32(s.ResponseP()) & ~KMMCOCRBusy);
722 OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT1, this, (TInt) KMMCErrNotSupported );
723 return KMMCErrNotSupported; // Card is incompatible with our h/w
725 iCurrentOpRange = range | (iCurrentOpRange & KMMCOCRAccessModeHCS);
728 // Repeat SEND_OP_COND this time setting Current Op Range
729 if (iCxCardType==ESDCardTypeIsMMC)
731 // If platform and the card both support low voltage mode (1.65 - 1.95v), switch
732 // NB If this fails then there is no recovery.
733 if (iCurrentOpRange & KMMCOCRLowVoltage)
735 iCurrentOpRange = KMMCOCRLowVoltage;
736 SMF_INVOKES( SwitchToLowVoltageSMST, EStSetRangeCmd )
740 SMF_STATE(EStSetRangeCmd)
742 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM11, "EStSetRangeCmd" );
743 // Issue ACMD41/CMD1 with voltage range
744 if (iCxCardType==ESDCardTypeIsMMC)
746 s.FillCommandDesc(ECmdSendOpCond,(iCurrentOpRange | KMMCOCRAccessModeHCS | KMMCOCRBusy)); // Range supported + Sector Access Busy bit (iArgument==KBit31)
747 SMF_NEXTS(EStSetRangeBusyCheck)
751 TUint arg = (iCurrentOpRange & ~KMMCOCRAccessModeHCS); // Range supported
752 if((iCurrentOpRange & KMMCOCRAccessModeHCS) != 0)
754 arg |= KMMCOCRAccessModeHCS;
756 DSDSession::FillAppCommandDesc(Command(), ESDACmdSDAppOpCond, arg);
757 SMF_NEXTS((iCxCardType == ESDCardTypeUnknown)? EStCheckForRangeCmd41Timeout : EStSetRangeBusyCheck)
760 m.SetTraps(KMMCErrResponseTimeOut);
761 SMF_CALL(ExecCommandSMST)
763 SMF_STATE(EStCheckForRangeCmd41Timeout)
765 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM12, "EStCheckForRangeCmd41Timeout" );
766 __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct:%d", err));
767 OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM13, "err=%d", (TInt) err);
768 if (err==KMMCErrResponseTimeOut)
770 iCxCardType=ESDCardTypeIsMMC;
771 // Send CMD0 to re-initialise the card - otherwise we may get
772 // KMMCStatErrIllegalCommand returned for the next command
773 // expecting an R1 response. NB The SD spec recommends ignoring the error
774 // whereas the SDIO spec recommends this approach (ignoring the error
775 // would be difficult to code anyway, since by then we're no longer
776 // in this state machine).
777 SMF_INVOKES(GoIdleSMST, EStSetRangeCmd); // Repeat - but using CMD1
781 // No response timeout - so it must be an SD Card
782 __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct2:%x", iCardArray));
783 __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct3:%x", iCxCardCount));
784 __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct4:%x", CardArray().CardP(iCxCardCount)));
785 OstTraceExt3(TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM14, "iCardArray=0x%x;iCxCardCount=%d;CardArray().CardP(iCxCardCount)=%d", (TUint) iCardArray, (TInt) iCxCardCount, (TInt) CardArray().CardP(iCxCardCount));
787 (CardArray().CardP(iCxCardCount)->iFlags)|=KSDCardIsSDCard;
788 iCxCardType=ESDCardTypeIsSD;
791 SMF_STATE(EStSetRangeBusyCheck)
793 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM15, "EStSetRangeBusyCheck" );
794 __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:src:%d",iCxCardType)); // 1:MMC, 2:SD
795 OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM16, "iCxCardType=%d", iCxCardType);
799 const TUint32 ocrResponse = TMMC::BigEndian32(s.ResponseP());
801 if ((ocrResponse & KMMCOCRBusy) == 0)
803 __KTRACE_OPT(KPBUS1,Kern::Printf("-sd:upd:bsy"));
804 // Card is still busy powering up. Check if we should timeout
805 if ( ++iCxPollRetryCount > iConfig.OpCondBusyTimeout() )
807 __KTRACE_OPT2(KPBUS1, KPANIC, Kern::Printf("-sd:ocr busy timed out"));
808 OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT2, this, (TInt) KMMCErrBusTimeOut );
809 return KMMCErrBusTimeOut;
813 if ( iCxPollRetryCount > KMMCSpecOpCondBusyTimeout )
815 __KTRACE_OPT2(KPBUS1, KPANIC, Kern::Printf("-sd:ocr exceeded spec timeout!! (%d ms)", (iCxPollRetryCount*KMMCRetryGapInMilliseconds)));
816 OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM17, "Exceeded spec timeout (%d ms)", (iCxPollRetryCount*KMMCRetryGapInMilliseconds));
821 SMF_INVOKES(RetryGapTimerSMST,EStSetRangeCmd)
825 if(ocrResponse & KMMCOCRAccessModeHCS)
827 CardArray().CardP(iCxCardCount)->iFlags |= KMMCardIsHighCapacity;
829 if(iCxCardType == ESDCardTypeIsSD)
831 __KTRACE_OPT(KPBUS1, Kern::Printf("Found large SD card."));
832 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM18, "Found large SD card" );
834 else if(iCxCardType == ESDCardTypeIsMMC)
836 __KTRACE_OPT(KPBUS1, Kern::Printf("Found large MMC card."));
837 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM19, "Found large MMC card" );
844 // Restore original settings
845 iConfig.SetMode( EffectiveModes(s.iConfig) & KMMCModeEnableTimeOutRetry );
846 iConfig.SetPollAttempts(KMMCMaxPollAttempts);
848 // All cards are now ready and notified of the voltage range - ask ASSP to set it up
849 if (iCxCardType==ESDCardTypeIsMMC)
851 iCurrentOpRange &= ~KMMCOCRAccessModeMask;
855 iCurrentOpRange &= ~KMMCOCRAccessModeHCS;
858 psu->SetVoltage(iCurrentOpRange);
859 if (psu->SetState(EPsuOnFull) != KErrNone)
861 OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT3, this, (TInt) KMMCErrHardware );
862 return KMMCErrHardware;
867 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM20, "EStCIDCmd" );
868 s.FillCommandDesc(ECmdAllSendCID,0);
870 SMF_INVOKES(ExecCommandSMST,EStSendCIDIssued)
872 SMF_STATE(EStSendCIDIssued)
874 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM21, "EStSendCIDIssued" );
875 // All done - Higher level state machine expects CID in s.ResponseP()
880 TMMCErr DSDStack::ConfigureMemoryCardSMST(TAny* aStackP)
881 { return static_cast<DSDStack*>(aStackP)->ConfigureMemoryCardSM(); }
883 TMMCErr DSDStack::ConfigureMemoryCardSM()
894 DMMCSession& s=Session();
895 OstTrace1( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM, "Current session = 0x%x", &s );
897 //coverity[UNREACHABLE]
898 //Part of state machine design.
901 OstTrace0( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM1, "EStBegin" );
902 // Cards is initialised so get its CSD
904 s.FillCommandDesc(ECmdSendCSD, TUint32(CardArray().CardP(iCxCardCount)->iRCA) << 16);
905 SMF_INVOKES(ExecCommandSMST, EStSendCSDDone)
907 SMF_STATE(EStSendCSDDone)
909 OstTrace0( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM2, "EStSendCSDDone" );
910 // Store the CSD in the new card entry
911 TMMCard* cardP = CardArray().CardP(iCxCardCount);
912 cardP->iCSD = s.ResponseP();
914 if(CardArray().Card(iCxCardCount).IsSDCard())
916 // Perform SD Specific parsing of the CSD structure
917 if(cardP->CSD().CCC() & KMMCCmdClassLockCard)
919 cardP->iFlags |= KMMCardIsLockable;
924 // Perform MMC Specific parsing of the CSD structure
925 TUint specVers = cardP->CSD().SpecVers(); // 1 => 1.4, 2 => 2.0 - 2.2, 3 => 3.1
926 if ((specVers >= 2) && (cardP->CSD().CCC() & KMMCCmdClassLockCard))
928 cardP->iFlags |= KMMCardIsLockable;
932 // Check the state of the mechanical write protect switch
933 if (WriteProtected(iCxCardCount))
935 cardP->iFlags |= KMMCardIsWriteProtected;
941 EXPORT_C TMMCErr DSDStack::InitStackAfterUnlockSM()
943 // Performs initialisation of the SD card after the card has been unlocked
957 EStCardDeselectedReadCSD,
963 DMMCSession& s=Session();
964 OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM, "Current session = 0x%x", &s );
968 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM1, "EStBegin" );
969 __KTRACE_OPT(KPBUS1, Kern::Printf(">DSDStack::InitStackAfterUnlockSM()"));
970 iRCAPool.ReleaseUnlocked();
971 iCxCardCount=0; // Reset current card number
973 SMF_STATE(EStNextCard)
974 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM2, "EStNextCard" );
975 AddressCard(iCxCardCount); // Address the next card
977 if (!CardDetect(iCxCardCount))
978 SMF_GOTOS(EStMoreCardsCheck)
980 s.SetCard(CardArray().CardP(iCxCardCount));
982 if (!CardArray().Card(iCxCardCount).IsSDCard())
984 SMF_INVOKES( DMMCStack::InitCurrentCardAfterUnlockSMST, EStMoreCardsCheck )
987 SMF_STATE(EStSelectCard)
989 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM3, "EStSelectCard" );
990 TRCA targetRCA = CardArray().Card(iCxCardCount).RCA();
991 if (targetRCA == SelectedCard())
993 SMF_GOTOS(EStSetBusWidth)
996 s.FillCommandDesc(ECmdSelectCard, targetRCA);
997 SMF_INVOKES(ExecCommandSMST,EStSetBusWidth)
999 SMF_STATE(EStSetBusWidth)
1000 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM4, "EStSetBusWidth" );
1001 const TMMCStatus status = s.LastStatus();
1002 if((status & KMMCStatCardIsLocked) != 0)
1003 SMF_GOTOS(EStDeselectCard)
1005 // set bus width with ACMD6
1006 TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16;
1007 s.FillCommandDesc(ECmdAppCmd, arg);
1008 SMF_INVOKES(IssueCommandCheckResponseSMST,EStSetBusWidth1)
1010 SMF_STATE(EStSetBusWidth1)
1011 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM5, "EStSetBusWidth1" );
1012 CardArray().Card(iCxCardCount).SetBusWidth(4);
1013 DSDSession::FillAppCommandDesc(Command(), ESDACmdSetBusWidth, KSDBusWidth4);
1014 SMF_INVOKES(IssueCommandCheckResponseSMST,EStGetSDStatus)
1016 SMF_STATE(EStGetSDStatus)
1017 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM6, "EStGetSDStatus" );
1018 // Now we have sent ACMD6, ask the controller to set the bus width to 4
1019 DoSetBusWidth(EBusWidth4);
1021 // get protected area size with ACMD13
1022 TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16;
1023 s.FillCommandDesc(ECmdAppCmd,arg);
1024 SMF_INVOKES(IssueCommandCheckResponseSMST,EStGetSDStatus1)
1026 SMF_STATE(EStGetSDStatus1)
1027 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM7, "EStGetSDStatus1" );
1028 DSDSession::FillAppCommandDesc(Command(), ESDACmdSDStatus);
1029 s.FillCommandArgs(0, KSDStatusBlockLength, iPSLBuf, KSDStatusBlockLength);
1030 SMF_INVOKES(IssueCommandCheckResponseSMST,EStDecodeSDStatus);
1032 SMF_STATE(EStDecodeSDStatus)
1033 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM8, "EStDecodeSDStatus" );
1035 for (TUint i = 0; i < KSDStatusBlockLength; ++i)
1037 __KTRACE_OPT(KPBUS1, Kern::Printf("SD_STATUS[0x%x] = %x", i, iPSLBuf[i]));
1038 OstTraceExt2( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM9, "SD_STATUS[0x%x]=0x%x", i, (TUint) iPSLBuf[i]);
1041 // bits 495:480 are SD_CARD_TYPE. Check this is 00xxh (x = don't care).
1043 if (iPSLBuf[2] != 0)
1045 OstTraceFunctionExitExt( DSDSTACK_INITSTACKAFTERUNLOCKSM_EXIT, this, (TInt) KMMCErrNotSupported );
1046 return KMMCErrNotSupported;
1049 // bits 479:448 contain SIZE_OF_PROTECTED_AREA.
1050 // (This is bytes 4 to 7 in big-endian format.)
1052 TSDCard& sdc = CardArray().Card(iCxCardCount);
1053 __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Card %d", iCxCardCount));
1054 TUint32 size_of_protected_area = TMMC::BigEndian32(&iPSLBuf[4]);
1055 __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: SizeOfProtectedArea: %d", size_of_protected_area));
1056 OstTraceExt2( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM10, "iCxCardCount=%d;SizeOfProtectedArea=%d", iCxCardCount, (TInt) size_of_protected_area);
1057 const TCSD& csd = sdc.CSD();
1060 if (sdc.IsHighCapacity())
1062 // High Capacity Card
1063 // Protected Area = SIZE_OF_PROTECTED_AREA
1064 pas = size_of_protected_area;
1065 __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack(SDHC): SetProtectedAreaSize: %d", pas));
1066 OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM11, "SDHC: SetProtectedAreaSize=%d", pas);
1070 // Standard Capacity Card
1071 // Protected Area = SIZE_OF_PROTECTED_AREA * C_SIZE_MULT * BLOCK_LEN
1072 pas = size_of_protected_area * (1 << (csd.CSizeMult() + 2 + csd.ReadBlLen()));
1073 __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack(SDSC): SetProtectedAreaSize: %d", pas));
1074 OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM12, "SDSC: SetProtectedAreaSize=%d", pas);
1077 sdc.SetProtectedAreaSize(pas);
1079 //bits 431:428 contain AU_SIZE
1080 //(This is higher order 4 bits of 10th byte in big endian format)
1081 TUint8 au = TUint8(iPSLBuf[10] >> 4);
1082 if(au == 0) //AU_SIZE field in SD status register is undefined.
1083 au = 6; //Defaulting to value corresponding to 512K
1086 SMF_INVOKES(SwitchToHighSpeedModeSMST, EStDeselectCard)
1088 SMF_STATE(EStDeselectCard)
1089 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM13, "EStDeselectCard" );
1090 s.FillCommandDesc(ECmdSelectCard, 0);
1091 SMF_INVOKES(ExecCommandSMST, EStCardDeselectedReadCSD)
1093 SMF_STATE(EStCardDeselectedReadCSD)
1094 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM14, "EStCardDeselectedReadCSD" );
1096 // Read the card's CSD register (again)
1098 // - We re-read the CSD, as the TRAN_SPEED field may have changed due to a switch to HS Mode
1100 TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16;
1101 s.FillCommandDesc( ECmdSendCSD, arg );
1102 SMF_INVOKES(ExecCommandSMST, EStCSDCmdSent)
1104 SMF_STATE(EStCSDCmdSent)
1105 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM15, "EStCSDCmdSent" );
1107 // Store the CSD in the card entry
1109 TMMCard* cardP = iCardArray->CardP(iCxCardCount);
1110 cardP->iCSD = s.ResponseP();
1112 SMF_STATE(EStMoreCardsCheck)
1113 OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM16, "EStMoreCardsCheck" );
1114 if (++iCxCardCount < (TInt)iMaxCardsInStack)
1116 __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Address Next card: %d",iCxCardCount));
1117 OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM17, "Address Next card=%d", iCxCardCount);
1118 SMF_GOTOS(EStNextCard)
1122 AddressCard(KBroadcastToAllCards);
1123 __KTRACE_OPT(KPBUS1, Kern::Printf("<DSDStack::InitStackAfterUnlockSM()"));
1130 TMMCErr DSDStack::CIMReadWriteMemoryBlocksSMST(TAny* aStackP)
1131 { return( static_cast<DSDStack *>(aStackP)->DMMCStack::CIMReadWriteBlocksSM() ); }
1134 EXPORT_C TMMCErr DSDStack::CIMReadWriteBlocksSM()
1136 // This macro performs single/multiple block reads and writes
1137 // For normal read/write block operations, this function determines the appropriate
1138 // MMC command to send and fills the command descriptor accordingly based on
1139 // the value of the session ID set. However, it is necessary to have set the
1140 // command arguments (with DMMCSession::FillCommandArgs()) before this function
1142 // For special block read/write operations, e.g. lock/unlock, it is required to
1143 // have already filled the command descriptor (with DMMCSession::FillCommandDesc())
1144 // for the special command required - in addition to have setup the command arguments.
1162 DMMCSession& s = Session();
1163 OstTrace1( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM, "Current session = 0x%x", &s );
1165 __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:RWBlocksSM %x",TUint(s.iLastStatus)));
1169 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM1, "EStBegin" );
1170 TSDCard& sdCard = *static_cast<TSDCard*>(s.iCardP);
1171 AddressCard(sdCard.iIndex-1);
1173 if(sdCard.IsSDCard() == EFalse)
1176 // If this is not an SD card, then use the more appropriate
1177 // MMC state machine as this is optimised for MMC performance
1179 SMF_INVOKES(CIMReadWriteMemoryBlocksSMST, EStDone);
1182 if(s.iSessionID == ECIMWriteBlock || s.iSessionID == ECIMWriteMBlock)
1184 // Check that the card supports class 4 (Write) commands
1185 const TUint ccc = s.iCardP->CSD().CCC();
1186 if(!(ccc & KMMCCmdClassBlockWrite))
1188 OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT, this, (TInt) KMMCErrNotSupported );
1189 return KMMCErrNotSupported;
1193 Command().iCustomRetries = 0; // MBW retries
1194 s.iState |= KMMCSessStateInProgress;
1195 m.SetTraps(KMMCErrInitContext);
1197 SMF_STATE(EStRestart) // NB: ErrBypass is not processed here
1199 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM2, "EStRestart" );
1200 SMF_CALLMEWR(EStRestart) // Create a recursive call entry to recover from the errors trapped
1201 m.SetTraps(KMMCErrStatus);
1202 if (s.Command().iSpec.iCommandClass!=KMMCCmdClassApplication || s.Command().iCommand==ECmdAppCmd )
1204 s.ResetCommandStack();
1205 SMF_INVOKES( AttachCardSMST, EStAttached ) // attachment is mandatory here
1208 SMF_BPOINT(EStAttached)
1210 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM3, "EStAttached" );
1211 TMMCCommandDesc& cmd = s.Command();
1213 const TUint32 blockLength = cmd.BlockLength();
1214 if((blockLength == 0) || (blockLength > (TUint)KDefaultBlockLenInBytes))
1216 __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:RWBlocksSM err BlockLen:%d",blockLength));
1217 OstTrace1( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM4, "blockLength=%d", blockLength );
1218 OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT1, this, (TInt) KMMCErrArgument );
1219 return KMMCErrArgument;
1222 if(s.iSessionID == ECIMReadBlock ||
1223 s.iSessionID == ECIMWriteBlock ||
1224 s.iSessionID == ECIMReadMBlock ||
1225 s.iSessionID == ECIMWriteMBlock)
1227 // read/write operation
1228 if(!cmd.AdjustForBlockOrByteAccess(s))
1230 // unable to convert command arguments to suit the underlying block/byte access mode
1231 OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT2, this, (TInt) KMMCErrArgument );
1232 return KMMCErrArgument;
1236 // Set the block length if it has changed. Always set for ECIMLockUnlock.
1237 if ((blockLength == s.iCardP->iSetBlockLen) && (s.iSessionID != ECIMLockUnlock))
1239 SMF_GOTOS( EStLengthSet )
1242 s.iCardP->iSetBlockLen = 0;
1243 s.PushCommandStack();
1244 s.FillCommandDesc( ECmdSetBlockLen, blockLength );
1245 SMF_INVOKES( ExecCommandSMST, EStLength1 )
1247 SMF_STATE(EStLength1)
1249 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM5, "EStLength1" );
1250 const TMMCStatus status(s.ResponseP());
1251 s.PopCommandStack();
1254 OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT3, this, (TInt) KMMCErrStatus );
1255 SMF_RETURN(KMMCErrStatus)
1257 s.iCardP->iSetBlockLen = s.Command().BlockLength();
1259 SMF_STATE(EStLengthSet)
1261 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM6, "EStLengthSet" );
1262 TMMCCommandDesc& cmd = s.Command();
1264 const TUint kTypeWrite = KBit0;
1265 const TUint kTypeMultiple = KBit1;
1266 const TUint kTypeSpecial = KBit2;
1267 static const TMMCCommandEnum cmdCodes[4] =
1268 {ECmdReadSingleBlock, ECmdWriteBlock, ECmdReadMultipleBlock, ECmdWriteMultipleBlock};
1270 switch( s.iSessionID )
1274 case ECIMWriteBlock:
1277 case ECIMReadMBlock:
1278 opType=kTypeMultiple;
1280 case ECIMWriteMBlock:
1281 opType=kTypeWrite|kTypeMultiple;
1283 case ECIMLockUnlock:
1285 opType=kTypeSpecial;
1289 const TUint blocks = cmd.iTotalLength / cmd.BlockLength();
1290 if ( blocks * cmd.BlockLength() != cmd.iTotalLength )
1292 OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT4, this, (TInt) KMMCErrArgument );
1293 return KMMCErrArgument;
1296 if ( !(opType & kTypeSpecial) ) // A special session has already set its command descriptor
1299 opType &= ~kTypeMultiple;
1301 TUint32 oldFlags = cmd.iFlags; // Store the existing command flags, as they will be reset by FillCommandDesc()
1302 cmd.iCommand = cmdCodes[opType];
1303 s.FillCommandDesc();
1304 cmd.iFlags = oldFlags; // ...and restore the old command flags
1307 // NB We need to trap KMMCErrStatus errors, because if one occurs,
1308 // we still need to wait to exit PRG/RCV/DATA state
1309 if (Command().iCommand == ECmdWriteMultipleBlock)
1311 Command().iExecNotHandle = KMMCErrDataCRC | KMMCErrDataTimeOut;
1312 m.SetTraps(KMMCErrStatus | KMMCErrDataCRC | KMMCErrDataTimeOut);
1316 m.SetTraps(KMMCErrStatus);
1319 SMF_INVOKES( ExecCommandSMST, EStIssued )
1321 SMF_STATE(EStIssued)
1323 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM7, "EStIssued" );
1324 // check state of card after data transfer with CMD13.
1325 if (s.Command().Direction() != 0)
1327 SMF_GOTOS(EStWaitFinish)
1330 SMF_GOTOS(EStRWFinish);
1332 SMF_STATE(EStWaitFinish)
1333 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM8, "EStWaitFinish" );
1334 // if MBW fail, then recover by rewriting ALL blocks...
1335 // (used to recover using ACMD22, but this has been changed
1336 // as is difficult to test for little gain in efficiency)
1337 if (Command().iCommand == ECmdWriteMultipleBlock && err != 0)
1339 if (Command().iCustomRetries++ >= (TInt) KSDMaxMBWRetries)
1341 OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT5, this, (TInt) err );
1345 m.Pop(); // remove recursive call to EStRestart
1346 SMF_GOTOS(EStRestart)
1349 // Save the status and examine it after issuing CMD13...
1350 // NB We don't know where in the command stack the last response is stored (e.g. there may
1351 // have bee a Deselect/Select issued), but we do know last response is stored in iLastStatus
1352 TMMC::BigEndian4Bytes(s.ResponseP(), s.iLastStatus);
1354 // ...else issue CMD13 to poll for the card finishing and check for errors
1355 s.PushCommandStack();
1356 s.FillCommandDesc(ECmdSendStatus, 0);
1357 SMF_INVOKES(ExecCommandSMST, EStWaitFinish1)
1359 SMF_STATE(EStWaitFinish1)
1361 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM9, "EStWaitFinish1" );
1362 const TMMCStatus status(s.ResponseP());
1363 s.PopCommandStack();
1366 SMF_GOTOS(EStRWFinish);
1368 const TMMCardStateEnum st1 = status.State();
1370 if (st1 == ECardStatePrg || st1 == ECardStateRcv || st1 == ECardStateData)
1372 SMF_INVOKES(ProgramTimerSMST, EStWaitFinish);
1377 OstTraceFunctionExitExt( DUP7_DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT, this, (TInt) KMMCErrStatus );
1378 SMF_RETURN(KMMCErrStatus)
1382 // Fall through if CURRENT_STATE is not PGM or DATA
1383 SMF_STATE(EStRWFinish)
1385 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM10, "EStRWFinish" );
1386 if (TMMCStatus(s.ResponseP()).Error() != 0)
1388 OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT6, this, (TInt) KMMCErrStatus );
1389 SMF_RETURN(KMMCErrStatus);
1392 s.iState &= ~KMMCSessStateInProgress;
1394 // skip over recursive entry or throw error and catch in CIMLockUnlockSM()
1395 TMMCErr ret = (s.Command().iCommand == ECmdLockUnlock) ? KMMCErrUpdPswd : KMMCErrBypass;
1396 OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT7, this, (TInt) ret );
1401 OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM11, "EStDone" );
1402 __KTRACE_OPT(KPBUS1,Kern::Printf("<SD:RWBlocksSM()"));
1407 EXPORT_C TMMCErr DSDStack::ModifyCardCapabilitySM()
1409 // This function provides a chance to modify the capability of paticular cards.
1410 // Licensee may overide this function to modify certain card's capability as needed.
1411 // A state machine is needed in derived function and function of base class should be
1412 // called in order to act more generic behaviour.
1422 //coverity[unreachable]
1423 //Part of state machine design.
1426 OstTrace0( TRACE_INTERNALS, DSDSTACK_MODIFYCARDCAPABILITYSM, "EStBegin" );
1427 SMF_INVOKES( DMMCStack::BaseModifyCardCapabilitySMST, EStDone )
1431 OstTrace0( TRACE_INTERNALS, DSDSTACK_MODIFYCARDCAPABILITYSM1, "EStDone" );
1436 inline TMMCErr DSDStack::SwitchToHighSpeedModeSMST( TAny* aStackP )
1437 { return( static_cast<DSDStack *>(aStackP)->DSDStack::SwitchToHighSpeedModeSM() ); }
1439 TMMCErr DSDStack::SwitchToHighSpeedModeSM()
1448 EStCheckFunctionSent,
1449 EStSwitchFunctionSent,
1454 __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:SwitchToHighSpeedModeSM "));
1456 DMMCSession& s = Session();
1457 OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM, "Current session = 0x%x", &s );
1461 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM1, "EStBegin");
1463 SMF_STATE(EstCheckController)
1464 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM2, "EstCheckController");
1465 // Get the clock speed supported by the controller
1466 TMMCMachineInfoV4 machineInfo;
1467 TMMCMachineInfoV4Pckg machineInfoPckg(machineInfo);
1468 MachineInfo(machineInfoPckg);
1470 if (machineInfo.iVersion >= TMMCMachineInfoV4::EVersion4)
1472 if (machineInfo.iMaxClockSpeedInMhz < (KSDDTClk50MHz/1000) )
1474 __KTRACE_OPT(KPBUS1, Kern::Printf("High speed mode not supported by controller"));
1475 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM3, "High speed mode not supported by controller");
1480 SMF_STATE(EStSendSCRCmd)
1481 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM4, "EStSendSCRCmd");
1483 // ACMD51 Read the SD Configuration Register
1485 DSDSession::FillAppCommandDesc(Command(), ESDACmdSendSCR);
1486 s.FillCommandArgs(0, KSDSCRLength, iPSLBuf, KSDSCRLength);
1487 SMF_INVOKES(ExecCommandSMST, EStCheckSpecVer);
1489 SMF_STATE(EStCheckSpecVer)
1490 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM5, "EStCheckSpecVer");
1492 // Check the SD version
1494 // 0 : version 1.0-1.01 : SDHS Is NOT Supported
1495 // 1 : version 1.10+ : SDHS Is Supported
1497 __KTRACE_OPT(KPBUS1,Kern::Printf(" SD Configuration Register received"));
1498 __KTRACE_OPT(KPBUS1,Kern::Printf(" ...card_status=%x", TUint(s.iLastStatus)));
1499 OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM6, "SD Configuration Register received: card_status=0x%x", (TUint) s.iLastStatus);
1502 for (TUint32 i = 0; i < KSDSCRLength; ++i)
1504 __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SCR_STATUS[0x%x] = %x", i, iPSLBuf[i]));
1510 __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 2"));
1511 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM7, "SD Spec Version 2");
1512 SMF_GOTOS(EStCheckFunction);
1517 __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 1.10"));
1518 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM8, "SD Spec Version 1.10");
1519 SMF_GOTOS(EStCheckFunction);
1524 __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 1.01"));
1525 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM9, "SD Spec Version 1.01");
1529 __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version > 2 !"));
1530 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM10, "SD Spec Version > 2");
1532 SMF_STATE(EStCheckFunction)
1534 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM11, "EStCheckFunction");
1535 m.SetTraps(KMMCErrResponseTimeOut | KMMCErrNotSupported);
1538 // SD1.1 uses CMD6 which is not defined by the MMCA
1539 // - fill in command details using the SD Specific command description table
1542 DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSwitchFunction);
1543 s.FillCommandArgs(KSDCheckFunctionHighSpeed, KSDSwitchFuncLength, iPSLBuf, KSDSwitchFuncLength);
1545 SMF_INVOKES(IssueCommandCheckResponseSMST,EStCheckFunctionSent)
1547 SMF_STATE(EStCheckFunctionSent)
1549 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM12, "EStCheckFunctionSent");
1550 __KTRACE_OPT(KPBUS1,Kern::Printf(" CheckFunctionSent %x",TUint(s.iLastStatus)));
1551 OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM13, "CheckFunctionSent=0x%x", (TUint) s.iLastStatus);
1555 if(err == KMMCErrResponseTimeOut)
1557 __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Read] Response Timeout"));
1558 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM14, "CMD6 [Read] Response Timeout");
1561 else if(err == KMMCErrNotSupported)
1563 __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Read] Not Supported"));
1564 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM15, "CMD6 [Read] Not Supported");
1569 for (TUint32 i = 0; i < KSDSwitchFuncLength; ++i)
1571 __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SD Switch Func Status[0x%x] = %x", i, iPSLBuf[i]));
1574 m.SetTraps(KMMCErrResponseTimeOut);
1578 // SD1.1 uses CMD6 which is not defined by the MMCA
1579 // - fill in command details using the SD Specific command description table
1582 DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSwitchFunction);
1583 s.FillCommandArgs(KSDSwitchFunctionHighSpeed, KSDSwitchFuncLength, iPSLBuf, KSDSwitchFuncLength);
1585 SMF_INVOKES(IssueCommandCheckResponseSMST,EStSwitchFunctionSent)
1587 SMF_STATE(EStSwitchFunctionSent)
1589 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM16, "EStSwitchFunctionSent");
1593 if(err == KMMCErrResponseTimeOut)
1595 __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Write] Response Timeout"));
1596 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM17, "CMD6 [Write] Response Timeout");
1599 for (TUint32 i = 0; i < KSDSwitchFuncLength; ++i)
1601 __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SD Switch[0x%x] = %x", i, iPSLBuf[i]));
1602 OstTraceExt2( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM18, "SD Switch[0x%x]=0x%x", (TUint) i, (TUint) iPSLBuf[i]);
1608 OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM19, "EStSwitchFunctionSent");
1614 EXPORT_C DMMCSession* DSDStack::AllocSession(const TMMCCallBack& aCallBack) const
1616 * Factory function to create DMMCSession derived object. Non-generic MMC
1617 * controllers can override this to generate more specific objects.
1618 * @param aCallBack Callback function to notify the client that a session has completed
1619 * @return A pointer to the new session
1622 OstTraceFunctionEntry1( DSDSTACK_ALLOCSESSION_ENTRY, this );
1623 return new DSDSession(aCallBack);
1626 EXPORT_C void DSDStack::Dummy1() {}
1627 EXPORT_C void DSDStack::Dummy2() {}
1628 EXPORT_C void DSDStack::Dummy3() {}
1629 EXPORT_C void DSDStack::Dummy4() {}