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.
14 // \e32\drivers\pbus\mmc\stack.cpp
18 #include <drivers/mmc.h>
19 #include <kernel/kern_priv.h>
20 #include <drivers/locmedia.h>
21 #include "stackbody.h"
23 #include "OstTraceDefinitions.h"
24 #ifdef OST_TRACE_COMPILER_IN_USE
25 #include "locmedia_ost.h"
27 #pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
29 #include "stackTraces.h"
33 TSpinLock MMCLock(TSpinLock::EOrderGenericIrqHigh0);
36 #define ASSERT_NOT_ISR_CONTEXT __ASSERT_DEBUG(NKern::CurrentContext()!=NKern::EInterrupt,DMMCSocket::Panic(DMMCSocket::EMMCUnblockingInWrongContext));
38 #if !defined(__WINS__)
39 #define DISABLEPREEMPTION TUint irq = __SPIN_LOCK_IRQSAVE(MMCLock);
40 #define RESTOREPREEMPTION __SPIN_UNLOCK_IRQRESTORE(MMCLock,irq);
42 #define DISABLEPREEMPTION
43 #define RESTOREPREEMPTION
46 //#define ENABLE_DETAILED_SD_COMMAND_TRACE
48 // default length of minor buffer - must have at least enough space for one sector
49 const TInt KMinMinorBufSize = 512;
51 // MultiMedia Card Controller - Generic level code for controller, intermediate
52 // level code for media change and power supply handling
54 EXPORT_C TUint TCSD::CSDField(const TUint& aTopBit, const TUint& aBottomBit) const
56 * Extract bitfield from CSD
59 const TUint indexT=KMMCCSDLength-1-aTopBit/8;
60 const TUint indexB=KMMCCSDLength-1-aBottomBit/8;
61 return(((indexT==indexB ? iData[indexT]
62 : (indexT+1)==indexB ? ((iData[indexT]<<8) | iData[indexT+1])
63 : ((iData[indexT]<<16) | (iData[indexT+1]<<8) | iData[indexT+2])
64 ) >> (aBottomBit&7)) & ((1<<(aTopBit-aBottomBit+1))-1));
68 // -------- class TCSD --------
69 // Raw field accessor functions are defined in mmc.inl. These functions return
70 // values that require extra computation, such as memory capacity.
73 EXPORT_C TUint TCSD::DeviceSize() const
76 * Calculate device capacity from CSD
78 * Section 5.3, MMCA Spec 2.2 (Jan 2000)
80 * memory capacity = BLOCKNR * BLOCK_LEN
82 * BLOCKNR = (C_SIZE + 1) * MULT; MULT = 2 ** (C_MULT_SIZE + 2);
83 * BLOCK_LEN = 2 ** (READ_BL_LEN)
85 * memory capacity = (C_SIZE + 1) * (2 ** (C_MULT_SIZE + 2)) * (2 ** READ_BL_LEN)
86 * = (C_SIZE + 1) * (2 ** (C_MULT_SIZE + 2 + READ_BL_LEN))
88 * @return Device Capacity
91 __KTRACE_OPT(KPBUS1, Kern::Printf("csd:ds:0x%x,0x%x,0x%x", ReadBlLen(), CSize(), CSizeMult()));
93 const TUint blockLog = ReadBlLen();
97 const TUint size = (CSize() + 1) << (2 + CSizeMult() + blockLog);
100 return( 0xFFF00000 );
105 EXPORT_C TMMCMediaTypeEnum TCSD::MediaType() const
107 * This function makes a rough approximation if media type based on supported
108 * command classes (CCC).
110 * @return TMMCMediaTypeEnum describing the type of media.
113 struct mediaTableEntry
117 TMMCMediaTypeEnum iMedia;
120 const TUint testMask = (KMMCCmdClassBlockRead|KMMCCmdClassBlockWrite|KMMCCmdClassErase|KMMCCmdClassIOMode);
121 static const mediaTableEntry mediaTable[] =
123 {KMMCCmdClassBasic, 0, EMultiMediaNotSupported},
124 {testMask, (KMMCCmdClassBlockRead|KMMCCmdClassBlockWrite|KMMCCmdClassErase), EMultiMediaFlash},
125 {testMask, KMMCCmdClassBlockRead|KMMCCmdClassBlockWrite, EMultiMediaFlash},
126 {testMask, KMMCCmdClassBlockRead|KMMCCmdClassErase, EMultiMediaROM},
127 {testMask, KMMCCmdClassBlockRead, EMultiMediaROM},
128 {KMMCCmdClassIOMode,KMMCCmdClassIOMode, EMultiMediaIO},
129 {0, 0, EMultiMediaOther}
132 const TUint ccc = CCC();
133 const mediaTableEntry* ptr = mediaTable;
135 while( (ccc & ptr->iMask) != (ptr->iValue) )
138 if (ptr->iMedia == EMultiMediaFlash)
140 // Further check PERM_WRITE_PROTECT and TMP_WRITE_PROTECT bits
141 if (PermWriteProtect() || TmpWriteProtect())
142 return EMultiMediaROM;
145 return( ptr->iMedia );
148 EXPORT_C TUint TCSD::ReadBlockLength() const
150 * Calculates the read block length from the CSD.
151 * READ_BL_LEN is encoded as a logarithm.
153 * @return The read block length
156 const TUint blockLog = ReadBlLen();
158 //SD version 2.0 or less the range is 0-11
159 //MMC version 4.1 or less the range is 0-11
160 //MMC version 4.2 the range is 0-14 (15 is reserved for future use)
161 //But we cannot differentiate among 4.x
162 //Hence , 0-14 is supported for 4.x
174 return( 1 << blockLog );
177 EXPORT_C TUint TCSD::WriteBlockLength() const
179 * Calculates the write block length from the CSD.
180 * WRITE_BL_LEN is encoded as a logarithm.
182 * @return The write block length
185 const TUint blockLog = WriteBlLen();
189 return( 1 << blockLog );
192 EXPORT_C TUint TCSD::EraseSectorSize() const
194 * Calculates the erase sector size from the CSD.
195 * SECTOR_SIZE is a 5 bit value, which is one less than the number of write
197 * @return The erase sector size
202 // V2.2 and earlier supports erase sectors. Read sector size from CSD(46:42) - confusingly now reassigned as
204 return( (EraseGrpSize()+1) * WriteBlockLength() );
208 // Support for erase sectors removed from V3.1 onwards
214 EXPORT_C TUint TCSD::EraseGroupSize() const
216 * Calculates the erase group size from the CSD.
217 * ERASE_GRP_SIZE is a 5 bit value, which is one less than the number of erase
218 * sectors in an erase group.
220 * @return The erase group size
225 // For V2.2 and earlier, the erase group size is held in CSD(41:37) - confusingly now reassigned as the erase
226 // group multiplier. The units for this are erase sectors, so need to convert to write blocks and then bytes.
227 TUint erSecSizeInBytes=(EraseGrpSize()+1) * WriteBlockLength();
228 return( (EraseGrpMult()+1) * erSecSizeInBytes );
232 // For V3.1 onwards, the erase group size is determined by multiplying the erase group size - CSD(41:37) by the
233 // erase group multiplier - CSD(46:42)). The units for this are write blocks, so need to convert to bytes.
234 TUint erGrpSizeInWrBlk = (EraseGrpSize()+1) * (EraseGrpMult()+1);
235 return(erGrpSizeInWrBlk * WriteBlockLength());
239 EXPORT_C TUint TCSD::MinReadCurrentInMilliamps() const
241 * Calculates the minimum read current from the CSD.
242 * VDD_R_CURR_MIN is a three bit value which is mapped to a number of mA.
243 * 0 actually maps to 0.5mA, but has been rounded up.
245 * @return The minimum read current, in Milliamps
248 static const TUint8 minConsumptionTable[] = {1,1,5,10,25,35,60,100};
249 return( minConsumptionTable[VDDRCurrMin()] );
252 EXPORT_C TUint TCSD::MinWriteCurrentInMilliamps() const
254 * Calculates the minimum write current from the CSD.
255 * VDD_W_CURR_MIN is a three bit value which is mapped to a number of mA.
257 * @return The minimum write current, in Milliamps
260 static const TUint8 minConsumptionTable[] = {1,1,5,10,25,35,60,100};
261 return( minConsumptionTable[VDDWCurrMin()] );
264 EXPORT_C TUint TCSD::MaxReadCurrentInMilliamps() const
266 * Calculates the maximum read current from the CSD.
267 * VDD_R_CURR_MAX is a three bit value which is mapped to a number of mA.
268 * 0 actually maps to 0.5mA, but has been rounded up.
270 * @return The maximum read current, in Milliamps
273 static const TUint8 maxConsumptionTable[] = {1,5,10,25,35,45,80,200};
274 return( maxConsumptionTable[VDDRCurrMax()] );
277 EXPORT_C TUint TCSD::MaxWriteCurrentInMilliamps() const
279 * Calculates the maximum write current from the CSD.
280 * VDD_W_CURR_MAX is a three bit value which is mapped to a number of mA.
282 * @return The maximum write current, in Milliamps
285 static const TUint8 maxConsumptionTable[] = {1,5,10,25,35,45,80,200};
286 return( maxConsumptionTable[VDDWCurrMax()] );
289 EXPORT_C TUint TCSD::MaxTranSpeedInKilohertz() const
291 * TRAN_SPEED is an eight bit value which encodes three fields.
292 * Section 5.3, MMCA Spec 2.2 (Jan 2000)
294 * 2:0 transfer rate unit values 4 to 7 are reserved.
297 * @return Speed, in Kilohertz
300 // tranRateUnits entries are all divided by ten so tranRateValues can be integers
301 static const TUint tranRateUnits[8] = {10,100,1000,10000,10,10,10,10};
302 static const TUint8 tranRateValues[16] = {10,10,12,13,15,20,25,30,35,40,45,50,55,60,70,80};
303 const TUint ts = TranSpeed();
304 return( tranRateUnits[ts&7] * tranRateValues[(ts>>3)&0xF] );
307 // -------- class TMMCard --------
310 : iIndex(0), iUsingSessionP(0), iFlags(0), iBusWidth(1)
315 EXPORT_C TBool TMMCard::IsReady() const
317 * Predicate for if card is mounted and in standby/transfer/sleep state.
319 * @return ETrue if ready, EFalse otherwise.
322 const TUint state = iStatus.State();
323 __KTRACE_OPT(KPBUS1, Kern::Printf("=mcc:ir:%d,0x%08x", IsPresent(), state));
324 OstTraceExt2( TRACE_INTERNALS, TMMCARD_ISREADY, "IsPresent=%d; state=0x%08x", IsPresent(), state );
326 return IsPresent() && (state == ECardStateStby || state == ECardStateTran || state == ECardStateSlp);
329 EXPORT_C TBool TMMCard::IsLocked() const
331 * Predicate for if card is locked
333 * It would be useful to check if the CSD supports the password protection
334 * feature. Password protection was introduced in c3.1, 05/99 and SPEC_VERS
335 * is encoded 0 |-> 1.0 - 1.2, 1 |-> 1.4, 3 |-> 2.2. Some cards support
336 * password locking but their CSD reports SPEC_VERS == 1.
338 * @return ETrue if locked, EFalse otherwise.
341 OstTraceFunctionEntry1( TMMCARD_ISLOCKED_ENTRY, this );
345 return( (TUint32(iStatus) & KMMCStatCardIsLocked) != 0 );
348 TInt64 TMMCard::DeviceSize64() const
350 * Returns the size of the MMC card in bytes
351 * @return The size of the MMC card in bytes.
354 OstTraceFunctionEntry1( TMMCARD_DEVICESIZE64_ENTRY, this );
355 const TBool highCapacity = IsHighCapacity();
356 const TUint32 sectorCount = ExtendedCSD().SectorCount();
358 return ((highCapacity && sectorCount) ? (((TInt64)ExtendedCSD().SectorCount()) * 512) : (TInt64)CSD().DeviceSize());
361 TUint32 TMMCard::PreferredWriteGroupLength() const
363 * Returns the write group length. Provided by the variant.
364 * Default implementation returns a multiple of the write block length, as indicated by the CSD.
365 * @return The preferred write group length.
368 OstTraceFunctionEntry1( TMMCARD_PREFERREDWRITEGROUPLENGTH_ENTRY, this );
369 return(CSD().WriteBlockLength() << 5); // 16K for a standard 512byte block length
372 TInt TMMCard::GetFormatInfo(TLDFormatInfo& /*aFormatInfo*/) const
374 * Returns the preferred format parametersm for the partition.
375 * Implemented at the Variant layer.
376 * @return Standard Symbian OS error code.
379 return KErrNotSupported;
382 TUint32 TMMCard::MinEraseSectorSize() const
384 * Returns the minimum erase sector size. Provided by the variant.
385 * Default implementation returns the erase sector size, as indicated by the CSD.
386 * @return The minimum erase sector size.
389 return CSD().EraseSectorSize();
392 TUint32 TMMCard::EraseSectorSize() const
394 * Returns the recommended erase sector size. Provided by the variant.
395 * Default implementation returns the erase sector size, as indicated by the CSD.
396 * @return The recommended erase sector size.
399 return CSD().EraseSectorSize();
402 LOCAL_C TBool IsPowerOfTwo(TInt aNum)
404 // Returns ETrue if aNum is a power of two
407 return (aNum != 0 && (aNum & -aNum) == aNum);
410 TInt TMMCard::GetEraseInfo(TMMCEraseInfo& aEraseInfo) const
412 * Return info. on erase services for this card
413 * @param aEraseInfo A reference to the TMMCEraseInfo to be filled in with the erase information.
414 * @return Symbian OS error code.
417 OstTraceFunctionEntry1( TMMCARD_GETERASEINFO_ENTRY, this );
419 // Check whether this card supports Erase Class Commands. Also, validate the erase group size
420 if ((CSD().CCC() & KMMCCmdClassErase) && IsPowerOfTwo(CSD().EraseGroupSize()))
422 // This card supports erase cmds. Also, all versions of MMC cards support Erase Group commands (i.e. CMD35, CMD36).
423 OstTrace0( TRACE_INTERNALS, TMMCARD_GETERASEINFO, "Card supports erase class commands" );
424 aEraseInfo.iEraseFlags=(KMMCEraseClassCmdsSupported|KMMCEraseGroupCmdsSupported);
426 // Return the preferred size to be used as the unit for format operations. We need to return a sensible
427 // multiple of the erase group size - as calculated by the CSD. A value around 1/32th of the total disk
428 // size generally results in an appropriate number of individual format calls.
429 const TInt64 devSizeDividedBy32=(DeviceSize64()>>5);
430 aEraseInfo.iPreferredEraseUnitSize=CSD().EraseGroupSize();
431 while (aEraseInfo.iPreferredEraseUnitSize < devSizeDividedBy32)
432 aEraseInfo.iPreferredEraseUnitSize<<=1;
434 // Return the smallest size that can be used as the unit for erase operations. For erase group commands, this
435 // is the erase group size.
436 aEraseInfo.iMinEraseSectorSize=CSD().EraseGroupSize();
439 aEraseInfo.iEraseFlags=0;
441 OstTraceFunctionExitExt( TMMCARD_GETERASEINFO_EXIT, this, KErrNone );
445 TUint TMMCard::MaxTranSpeedInKilohertz() const
447 * Returns the maximum supported clock rate for the card, in Kilohertz.
448 * @return Speed, in Kilohertz
451 OstTraceFunctionEntry1( TMMCARD_MAXTRANSPEEDINKILOHERTZ_ENTRY, this );
452 // Default implementation obtains the transaction speed from the CSD
453 TUint32 highSpeedClock = HighSpeedClock();
454 return(highSpeedClock ? highSpeedClock : iCSD.MaxTranSpeedInKilohertz());
458 TInt TMMCard::MaxReadBlLen() const
460 * Returns the maximum read block length supported by the card encoded as a logarithm
461 * Normally this is the same as the READ_BL_LEN field in the CSD register,
462 * but for high capacity cards (>- 2GB) this is set to a maximum of 512 bytes,
463 * if possible, to try to avoid compatibility issues.
466 OstTraceFunctionEntry1( TMMCARD_MAXREADBLLEN_ENTRY, this );
467 const TInt KDefaultReadBlockLen = 9; // 2^9 = 512 bytes
468 const TCSD& csd = CSD();
470 TInt blkLenLog2 = csd.ReadBlLen();
472 if (blkLenLog2 > KDefaultReadBlockLen)
474 __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl %d", blkLenLog2));
475 OstTrace1( TRACE_INTERNALS, TMMCARD_MAXREADBLLEN1, "Block length 1=%d", blkLenLog2 );
478 if (csd.ReadBlPartial() || CSD().SpecVers() >= 4)
481 // MMC System Spec 4.2 states that 512 bytes blocks are always supported,
482 // regardless of the state of READ_BL_PARTIAL
484 blkLenLog2 = KDefaultReadBlockLen;
485 __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl -> %d", blkLenLog2));
486 OstTrace1( TRACE_INTERNALS, TMMCARD_MAXREADBLLEN2, "Block length 2=%d", blkLenLog2 );
490 OstTraceFunctionExitExt( TMMCARD_MAXREADBLLEN_EXIT, this, blkLenLog2 );
495 TInt TMMCard::MaxWriteBlLen() const
497 * Returns the maximum write block length supported by the card encoded as a logarithm
498 * Normally this is the same as the WRITE_BL_LEN field in the CSD register,
499 * but for high capacity cards (>- 2GB) this is set to a maximum of 512 bytes,
500 * if possible, to try to avoid compatibility issues.
503 OstTraceFunctionEntry1( TMMCARD_MAXWRITEBLLEN_ENTRY, this );
504 const TInt KDefaultWriteBlockLen = 9; // 2^9 = 512 bytes
505 const TCSD& csd = CSD();
507 TInt blkLenLog2 = csd.WriteBlLen();
509 if (blkLenLog2 > KDefaultWriteBlockLen)
511 __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl %d", blkLenLog2));
512 OstTrace1( TRACE_INTERNALS, TMMCARD_MAXWRITEBLLEN1, "Block length 1=%d", blkLenLog2 );
513 if (csd.WriteBlPartial() || CSD().SpecVers() >= 4)
516 // MMC System Spec 4.2 states that 512 bytes blocks are always supported,
517 // regardless of the state of READ_BL_PARTIAL
519 blkLenLog2 = KDefaultWriteBlockLen;
520 __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl -> %d", blkLenLog2));
521 OstTrace1( TRACE_INTERNALS, TMMCARD_MAXWRITEBLLEN2, "Block length 1=%d", blkLenLog2 );
525 OstTraceFunctionExitExt( TMMCARD_MAXWRITEBLLEN_EXIT, this, blkLenLog2 );
530 // -------- class TMMCardArray --------
532 EXPORT_C TInt TMMCardArray::AllocCards()
534 * Allocate TMMCard objects for iCards and iNewCardsArray.
535 * This function is called at bootup as part of stack allocation so there
536 * is no cleanup if it fails.
538 * @return KErrNone if successful, Standard Symbian OS error code otherwise.
541 OstTraceFunctionEntry1( TMMCARDARRAY_ALLOCCARDS_ENTRY, this );
542 for (TUint i = 0; i < KMaxMMCardsPerStack; ++i)
544 // zeroing the card data used to be implicit because embedded in
545 // CBase-derived DMMCStack.
546 if ((iCards[i] = new TMMCard) == 0)
548 OstTraceFunctionExitExt( TMMCARDARRAY_ALLOCCARDS_EXIT1, this, KErrNoMemory );
551 iCards[i]->iUsingSessionP = 0;
552 if ((iNewCards[i] = new TMMCard) == 0)
554 OstTraceFunctionExitExt( TMMCARDARRAY_ALLOCCARDS_EXIT2, this, KErrNoMemory );
557 iNewCards[i]->iUsingSessionP = 0;
560 OstTraceFunctionExitExt( TMMCARDARRAY_ALLOCCARDS_EXIT3, this, KErrNone );
564 void TMMCardArray::InitNewCardScan()
566 * Prepare card array for new scan.
569 OstTraceFunctionEntry1( TMMCARDARRAY_INITNEWCARDSCAN_ENTRY, this );
571 OstTraceFunctionExit1( TMMCARDARRAY_INITNEWCARDSCAN_EXIT, this );
574 void TMMCardArray::MoveCardAndLockRCA(TMMCard& aSrcCard,TMMCard& aDestCard,TInt aDestIndex)
576 * Copy card object and lock RCA.
579 OstTraceExt2(TRACE_FLOW, TMMCARDARRAY_MOVECARDANDLOCKRCA_ENTRY, "TMMCardArray::MoveCardAndLockRCA;aDestIndex=%d;this=%x", aDestIndex, (TUint) this);
580 __KTRACE_OPT(KPBUS1, Kern::Printf("=mca:mclr:%d", aDestIndex));
582 aDestCard.iCID=aSrcCard.iCID;
583 aDestCard.iRCA=aSrcCard.iRCA;
584 aDestCard.iCSD=aSrcCard.iCSD;
585 aDestCard.iIndex=aDestIndex; // Mark card as being present
586 aDestCard.iFlags=aSrcCard.iFlags;
587 aDestCard.iBusWidth=aSrcCard.iBusWidth;
588 aDestCard.iHighSpeedClock = aSrcCard.iHighSpeedClock;
590 iOwningStack->iRCAPool.LockRCA(aDestCard.iRCA);
592 // Now that we have transferred ownership, reset the source card
593 aSrcCard.iRCA = aSrcCard.iIndex = aSrcCard.iFlags = 0;
594 aSrcCard.iBusWidth = 1;
595 aSrcCard.iHighSpeedClock = 0;
597 aSrcCard.iUsingSessionP = NULL;
598 OstTraceFunctionExit1( TMMCARDARRAY_MOVECARDANDLOCKRCA_EXIT, this );
601 EXPORT_C void TMMCardArray::AddNewCard(const TUint8* aCID,TRCA* aNewRCA)
603 * Found a new card to add to the array. Add it to a separate array for now
604 * since we need to know all the cards present before we start replacing old
608 OstTraceFunctionEntryExt( TMMCARDARRAY_ADDNEWCARD_ENTRY, this );
609 // Store the CID in the next free slot
610 NewCard(iNewCardsCount).iCID = aCID;
614 // Now let's look if we've seen this card before
615 for ( TUint i=0 ; i<iOwningStack->iMaxCardsInStack ; i++ )
617 if ( Card(i).iCID==NewCard(iNewCardsCount).iCID )
619 *aNewRCA=Card(i).iRCA;
620 NewCard(iNewCardsCount).iIndex=(i+1);
627 // Not seen this one before so get a new RCA for the card
628 NewCard(iNewCardsCount).iIndex=0;
629 __ASSERT_ALWAYS( (*aNewRCA=iOwningStack->iRCAPool.GetFreeRCA())!=0,DMMCSocket::Panic(DMMCSocket::EMMCNoFreeRCA) );
632 __KTRACE_OPT(KPBUS1, Kern::Printf("mca:adn: assigning new card %d rca 0x%04x", iNewCardsCount, TUint16(*aNewRCA) ));
633 OstTraceExt2( TRACE_INTERNALS, TMMCARDARRAY_ADDNEWCARD, "iNewCardsCount=%d; RCA=0x%04x", iNewCardsCount, (TUint) *aNewRCA );
635 NewCard(iNewCardsCount).iRCA=*aNewRCA;
637 OstTraceFunctionExit1( TMMCARDARRAY_ADDNEWCARD_EXIT, this );
640 TInt TMMCardArray::MergeCards(TBool aFirstPass)
642 * This function places newly acquired cards from the new card array into free
643 * slots of the main card array.
644 * Returns KErrNotFound if not able to successfully place all the new cards.
647 OstTraceFunctionEntryExt( TMMCARDARRAY_MERGECARDS_ENTRY, this );
650 __KTRACE_OPT(KPBUS1,Kern::Printf("=mca:mc:%d,%d", aFirstPass, iNewCardsCount));
651 OstTrace1( TRACE_INTERNALS, TMMCARDARRAY_MERGECARDS1, "iNewCardsCount=%d", iNewCardsCount );
653 TUint i; // New card index
654 TUint j; // Main card index
656 // Only do this on first pass. Setup any new cards which were already there
659 for ( i=0 ; i<iNewCardsCount ; i++ )
661 __KTRACE_OPT(KPBUS1, Kern::Printf("-mca:fp,i=%d,idx=0x%x", i, NewCard(i).iIndex));
662 OstTraceExt2( TRACE_INTERNALS, TMMCARDARRAY_MERGECARDS2, "i=%d; Index=0x%x", i, NewCard(i).iIndex );
663 if( NewCard(i).iIndex != 0 ) // Signifies card was here before (iIndex has old slot number +1)
665 // Put it in the same slot as before
666 j=(NewCard(i).iIndex-1);
667 MoveCardAndLockRCA(NewCard(i),Card(j),(j+1));
672 for ( i=0,j=0 ; i<iNewCardsCount ; i++ )
674 __KTRACE_OPT(KPBUS1, Kern::Printf("-mca:i=%d,j=%d,rca=0x%4x", i, j, TUint16(NewCard(i).iRCA) ));
675 if ( NewCard(i).iRCA != 0 )
677 // Find a spare slot in main array for this new card
678 while ( Card(j).IsPresent() )
679 if ( ++j==iOwningStack->iMaxCardsInStack )
681 OstTraceFunctionExitExt( TMMCARDARRAY_MERGECARDS_EXIT1, this, KErrNotFound );
685 // Found a free slot; move the card info there
686 __KTRACE_OPT(KPBUS1, Kern::Printf("-mca:freej=%d,rca=0x%04x", j, TUint16(Card(j).iRCA) ));
687 OstTraceExt2( TRACE_INTERNALS, TMMCARDARRAY_MERGECARDS3, "j=%d; RCA=0x%04x", j, (TUint) (Card(j).iRCA) );
688 if ( Card(j).iRCA != 0 )
689 iOwningStack->iRCAPool.UnlockRCA(Card(j).iRCA);
691 __KTRACE_OPT(KPBUS1, Kern::Printf("merging new card %d to card %d dest index %d", i, j, j+1));
692 OstTraceExt3( TRACE_INTERNALS, TMMCARDARRAY_MERGECARDS4, "Merging new card %d to card %d; Destination index=%d", (TInt) i, (TInt) j, (TInt) j+1 );
693 MoveCardAndLockRCA(NewCard(i),Card(j),(j+1));
696 OstTraceFunctionExitExt( TMMCARDARRAY_MERGECARDS_EXIT2, this, KErrNone );
700 void TMMCardArray::UpdateAcquisitions(TUint* aMaxClock)
702 * Called when we have successfully stored a new set of cards in the card array.
703 * This performs final initialisation of the card entries and determines the
704 * maximum bus clock that can be employed - by checking the CSD of each card.
707 OstTraceFunctionEntryExt( TMMCARDARRAY_UPDATEACQUISITIONS_ENTRY, this );
709 __KTRACE_OPT(KPBUS1,Kern::Printf("=mca:uda"));
711 TUint maxClk = iOwningStack->iMultiplexedBus ? 1 : 800000; // ???
712 for ( TUint i=0 ; i < (iOwningStack->iMaxCardsInStack) ; i++ )
714 if ( Card(i).IsPresent() )
716 // General initialisation
718 Card(i).iSetBlockLen=0;
719 Card(i).iLastCommand=ECmdSendStatus;
721 // Check each card present to determine appropriate bus clock
722 TUint maxTS = iOwningStack->MaxTranSpeedInKilohertz(Card(i));
723 if(iOwningStack->iMultiplexedBus)
725 if ( maxTS > maxClk )
730 if ( maxTS < maxClk )
735 // ??? Should also calculate here and return the data timeout and busy timeout
736 // instead of relying on ASSP defaults.
739 OstTraceFunctionExit1( TMMCARDARRAY_UPDATEACQUISITIONS_EXIT, this );
742 EXPORT_C void TMMCardArray::DeclareCardAsGone(TUint aCardNumber)
744 * Clears up a card info object in the main card array
747 OstTraceFunctionEntryExt( TMMCARDARRAY_DECLARECARDASGONE_ENTRY, this );
749 __KTRACE_OPT(KPBUS1,Kern::Printf("=mca:dcag"));
750 // If we thought this one was present then mark it as not present
751 TMMCard& card = Card(aCardNumber);
752 if (card.IsPresent())
754 card.iIndex=0; // Mark card as not present
758 // If this card is in use by a session then flag that card has now gone
759 if( card.iUsingSessionP != NULL )
760 card.iUsingSessionP->iState |= KMMCSessStateCardIsGone;
762 card.iUsingSessionP=NULL;
764 card.iFlags=0; // Reset 'has password' and 'write protected' bit fields
765 card.iHighSpeedClock=0;
767 OstTraceFunctionExit1( TMMCARDARRAY_DECLARECARDASGONE_EXIT, this );
770 // return this card's index in the array or KErrNotFound if not found
771 TInt TMMCardArray::CardIndex(const TMMCard* aCard)
773 OstTraceFunctionEntryExt( TMMCARDARRAY_CARDINDEX_ENTRY, this );
775 for (i = KMaxMMCardsPerStack-1; i>= 0; i--)
777 if (iCards[i] == aCard)
780 OstTraceFunctionExitExt( TMMCARDARRAY_CARDINDEX_EXIT, this, i );
784 // -------- class TMMCCommandDesc --------
786 EXPORT_C TInt TMMCCommandDesc::Direction() const
788 * returns -1, 0 or +1 for DT directions read, none or write respectively
791 OstTraceFunctionEntry1( TMMCCOMMANDDESC_DIRECTION_ENTRY, this );
792 TUint dir = iSpec.iDirection;
799 OstTraceFunctionExitExt( TMMCCOMMANDDESC_DIRECTION_EXIT1, this, ret );
803 if( dir & KMMCCmdDirWBitArgument )
804 result = TUint(iArgument) >> (dir & KMMCCmdDirIndBitPosition);
806 if( dir & KMMCCmdDirNegate )
809 ret = ((result&1)-1)|1;
811 OstTraceFunctionExitExt( TMMCCOMMANDDESC_DIRECTION_EXIT2, this, ret );
816 TBool TMMCCommandDesc::AdjustForBlockOrByteAccess(const DMMCSession& aSession)
818 OstTraceExt2(TRACE_FLOW, TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_ENTRY, "TMMCCommandDesc::AdjustForBlockOrByteAccess;Session ID=%d;this=%x", (TInt) aSession.SessionID(), (TUint) this);
820 * The MMC session provides both block and byte based IO methods, all of which can
821 * be used on both block and byte based MMC cards. This method adjusts the command
822 * arguments so that they match the underlying cards access mode.
824 * @return ETrue if the address is valid or successfully converted, EFalse otherwise
826 TUint32 blockLength = BlockLength();
828 if(iTotalLength == 0 ||
830 iTotalLength % KMMCardHighCapBlockSize != 0 || // always aligned on 512 bytes
831 blockLength % KMMCardHighCapBlockSize != 0)
833 OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT1, this, (TUint) EFalse );
837 if(aSession.CardP()->IsHighCapacity())
839 // high capacity (block-based) card
840 if((iFlags & KMMCCmdFlagBlockAddress) == 0)
842 // The command arguments are using byte based addressing
843 // - adjust to block-based addressing
844 if(iArgument % KMMCardHighCapBlockSize != 0)
846 // Block based media does not support misaligned access
847 OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT2, this, (TUint) EFalse );
851 // adjust for block based access
852 iArgument = iArgument >> KMMCardHighCapBlockSizeLog2;
853 iFlags |= KMMCCmdFlagBlockAddress;
858 // standard (byte based) card
859 if((iFlags & KMMCCmdFlagBlockAddress) != 0)
861 // The command arguments are using block based addressing
862 // - adjust to byte-based addressing
863 const TUint32 maxBlocks = 4 * 1024 * ((1024 * 1024) >> KMMCardHighCapBlockSizeLog2);
865 if(iArgument > maxBlocks)
867 // The address is out of range (>2G) - cannot convert
868 OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT3, this, (TUint) EFalse );
872 // adjust for byte-based access
873 iArgument = iArgument << KMMCardHighCapBlockSizeLog2;
874 iFlags &= ~KMMCCmdFlagBlockAddress;
876 else if(iArgument % KMMCardHighCapBlockSize != 0)
878 // byte addressing, unaligned address
879 OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT4, this, (TUint) EFalse );
884 OstTraceFunctionExitExt( TMMCCOMMANDDESC_ADJUSTFORBLOCKORBYTEACCESS_EXIT5, this, (TUint) ETrue );
888 void TMMCCommandDesc::Dump(TUint8* aResponseP, TMMCErr aErr)
891 Kern::Printf("------------------------------------------------------------------");
892 Kern::Printf("CMD %02d(0x%08x) - ",TUint(iCommand),TUint(iArgument));
896 case 0 : Kern::Printf(" | GO_IDLE_STATE"); break;
897 case 1 : Kern::Printf(" | SEND_OP_COND"); break;
898 case 2 : Kern::Printf(" | ALL_SEND_CID"); break;
899 case 3 : Kern::Printf(" | SET_RELATIVE_ADDR"); break;
900 case 4 : Kern::Printf(" | SET_DSR"); break;
901 case 5 : Kern::Printf(" | SLEEP/AWAKE"); break;
902 case 6 : Kern::Printf(" | SWITCH"); break;
903 case 7 : Kern::Printf(" | SELECT/DESELECT_CARD"); break;
904 case 8 : Kern::Printf(" | SEND_EXT_CSD"); break;
905 case 9 : Kern::Printf(" | SEND_CSD"); break;
906 case 10 : Kern::Printf(" | SEND_CID"); break;
907 case 11 : Kern::Printf(" | READ_DAT_UNTIL_STOP"); break;
908 case 12 : Kern::Printf(" | STOP_TRANSMISSION"); break;
909 case 13 : Kern::Printf(" | SEND_STATUS"); break;
910 case 14 : Kern::Printf(" | BUSTEST_R"); break;
911 case 15 : Kern::Printf(" | GO_INACTIVE_STATE"); break;
912 case 16 : Kern::Printf(" | SET_BLOCKLEN"); break;
913 case 17 : Kern::Printf(" | READ_SINGLE_BLOCK"); break;
914 case 18 : Kern::Printf(" | READ_MULTIPLE_BLOCK"); break;
915 case 19 : Kern::Printf(" | BUSTEST_W"); break;
916 case 20 : Kern::Printf(" | WRITE_DAT_UNTIL_STOP"); break;
917 case 23 : Kern::Printf(" | SET_BLOCK_COUNT"); break;
918 case 24 : Kern::Printf(" | WRITE_BLOCK"); break;
919 case 25 : Kern::Printf(" | WRITE_MULTIPLE_BLOCK"); break;
920 case 26 : Kern::Printf(" | PROGRAM_CID"); break;
921 case 27 : Kern::Printf(" | PROGRAM_CSD"); break;
922 case 28 : Kern::Printf(" | SET_WRITE_PROT"); break;
923 case 29 : Kern::Printf(" | CLR_WRITE_PROT"); break;
924 case 30 : Kern::Printf(" | SEND_WRITE_PROT"); break;
925 case 32 : Kern::Printf(" | ERASE_WR_BLK_START"); break; // SD
926 case 33 : Kern::Printf(" | ERASE_WR_BLK_END"); break; // SD
927 case 35 : Kern::Printf(" | ERASE_GROUP_START"); break;
928 case 36 : Kern::Printf(" | ERASE_GROUP_END"); break;
929 case 38 : Kern::Printf(" | ERASE"); break;
930 case 39 : Kern::Printf(" | FAST_IO"); break;
931 case 40 : Kern::Printf(" | GO_IRQ_STATE"); break;
932 case 42 : Kern::Printf(" | LOCK_UNLOCK"); break;
933 case 55 : Kern::Printf(" | APP_CMD"); break;
934 case 56 : Kern::Printf(" | GEN_CMD"); break;
935 default : Kern::Printf(" | *** UNKNOWN COMMAND ***"); break;
938 switch(iSpec.iResponseType)
940 case ERespTypeNone: Kern::Printf(" RSP - NONE"); break;
941 case ERespTypeUnknown: Kern::Printf(" RSP - UNKNOWN"); break;
942 case ERespTypeR1: Kern::Printf(" RSP - R1"); break;
943 case ERespTypeR1B: Kern::Printf(" RSP - R1b"); break;
944 case ERespTypeR2: Kern::Printf(" RSP - R2"); break;
945 case ERespTypeR3: Kern::Printf(" RSP - R3"); break;
946 case ERespTypeR4: Kern::Printf(" RSP - R4"); break;
947 case ERespTypeR5: Kern::Printf(" RSP - R5"); break;
948 case ERespTypeR6: Kern::Printf(" RSP - R6"); break;
949 default : Kern::Printf(" RSP - *** UNKNOWN RESPONSE ***"); break;
952 switch(iSpec.iResponseLength)
955 case 4 : Kern::Printf(" | 0x%08x", TMMC::BigEndian32(aResponseP)); break;
956 case 16 : Kern::Printf(" | 0x%08x 0x%08x 0x%08x 0x%08x", ((TUint32*)aResponseP)[0], ((TUint32*)aResponseP)[1], ((TUint32*)aResponseP)[2], ((TUint32*)aResponseP)[3]); break;
957 default : Kern::Printf(" | *** RESPONSE NOT PARSED ***"); break;
959 Kern::Printf(" ERR - 0x%08x", aErr);
960 if(aErr & KMMCErrResponseTimeOut) Kern::Printf(" | KMMCErrResponseTimeOut");
961 if(aErr & KMMCErrDataTimeOut) Kern::Printf(" | KMMCErrDataTimeOut");
962 if(aErr & KMMCErrBusyTimeOut) Kern::Printf(" | KMMCErrBusyTimeOut");
963 if(aErr & KMMCErrBusTimeOut) Kern::Printf(" | KMMCErrBusTimeOut");
964 if(aErr & KMMCErrTooManyCards) Kern::Printf(" | KMMCErrTooManyCards");
965 if(aErr & KMMCErrResponseCRC) Kern::Printf(" | KMMCErrResponseCRC");
966 if(aErr & KMMCErrDataCRC) Kern::Printf(" | KMMCErrDataCRC");
967 if(aErr & KMMCErrCommandCRC) Kern::Printf(" | KMMCErrCommandCRC");
968 if(aErr & KMMCErrStatus) Kern::Printf(" | KMMCErrStatus");
969 if(aErr & KMMCErrNoCard) Kern::Printf(" | KMMCErrNoCard");
970 if(aErr & KMMCErrBrokenLock) Kern::Printf(" | KMMCErrBrokenLock");
971 if(aErr & KMMCErrPowerDown) Kern::Printf(" | KMMCErrPowerDown");
972 if(aErr & KMMCErrAbort) Kern::Printf(" | KMMCErrAbort");
973 if(aErr & KMMCErrStackNotReady) Kern::Printf(" | KMMCErrStackNotReady");
974 if(aErr & KMMCErrNotSupported) Kern::Printf(" | KMMCErrNotSupported");
975 if(aErr & KMMCErrHardware) Kern::Printf(" | KMMCErrHardware");
976 if(aErr & KMMCErrBusInconsistent) Kern::Printf(" | KMMCErrBusInconsistent");
977 if(aErr & KMMCErrBypass) Kern::Printf(" | KMMCErrBypass");
978 if(aErr & KMMCErrInitContext) Kern::Printf(" | KMMCErrInitContext");
979 if(aErr & KMMCErrArgument) Kern::Printf(" | KMMCErrArgument");
980 if(aErr & KMMCErrSingleBlock) Kern::Printf(" | KMMCErrSingleBlock");
981 if(aErr & KMMCErrUpdPswd) Kern::Printf(" | KMMCErrUpdPswd");
982 if(aErr & KMMCErrLocked) Kern::Printf(" | KMMCErrLocked");
983 if(aErr & KMMCErrNotFound) Kern::Printf(" | KMMCErrNotFound");
984 if(aErr & KMMCErrAlreadyExists) Kern::Printf(" | KMMCErrAlreadyExists");
985 if(aErr & KMMCErrGeneral) Kern::Printf(" | KMMCErrGeneral");
988 if(iSpec.iResponseType == ERespTypeR1 || iSpec.iResponseType == ERespTypeR1B)
990 const TUint32 stat = TMMC::BigEndian32(aResponseP);
992 Kern::Printf(" STAT - 0x%08x", stat);
993 if(stat & KMMCStatAppCmd) Kern::Printf(" | KMMCStatAppCmd");
994 if(stat & KMMCStatSwitchError) Kern::Printf(" | KMMCStatSwitchError");
995 if(stat & KMMCStatReadyForData) Kern::Printf(" | KMMCStatReadyForData");
996 if(stat & KMMCStatCurrentStateMask){ Kern::Printf(" | KMMCStatCurrentStateMask");
997 const TMMCardStateEnum cardState = (TMMCardStateEnum)(stat & KMMCStatCurrentStateMask);
999 case ECardStateIdle : Kern::Printf(" | ECardStateIdle"); break;
1000 case ECardStateReady : Kern::Printf(" | ECardStateReady"); break;
1001 case ECardStateIdent : Kern::Printf(" | ECardStateIdent"); break;
1002 case ECardStateStby : Kern::Printf(" | ECardStateStby"); break;
1003 case ECardStateTran : Kern::Printf(" | ECardStateTran"); break;
1004 case ECardStateData : Kern::Printf(" | ECardStateData"); break;
1005 case ECardStateRcv : Kern::Printf(" | ECardStateRcv"); break;
1006 case ECardStatePrg : Kern::Printf(" | ECardStatePrg"); break;
1007 case ECardStateDis : Kern::Printf(" | ECardStateDis"); break;
1008 case ECardStateBtst : Kern::Printf(" | ECardStateBtst"); break;
1009 case ECardStateSlp : Kern::Printf(" | ECardStateSlp"); break;
1010 default : Kern::Printf(" | ECardStateUnknown"); break;
1013 if(stat & KMMCStatEraseReset) Kern::Printf(" | KMMCStatEraseReset");
1014 if(stat & KMMCStatCardECCDisabled) Kern::Printf(" | KMMCStatCardECCDisabled");
1015 if(stat & KMMCStatWPEraseSkip) Kern::Printf(" | KMMCStatWPEraseSkip");
1016 if(stat & KMMCStatErrCSDOverwrite) Kern::Printf(" | KMMCStatErrCSDOverwrite");
1017 if(stat & KMMCStatErrOverrun) Kern::Printf(" | KMMCStatErrOverrun");
1018 if(stat & KMMCStatErrUnderrun) Kern::Printf(" | KMMCStatErrUnderrun");
1019 if(stat & KMMCStatErrUnknown) Kern::Printf(" | KMMCStatErrUnknown");
1020 if(stat & KMMCStatErrCCError) Kern::Printf(" | KMMCStatErrCCError");
1021 if(stat & KMMCStatErrCardECCFailed) Kern::Printf(" | KMMCStatErrCardECCFailed");
1022 if(stat & KMMCStatErrIllegalCommand) Kern::Printf(" | KMMCStatErrIllegalCommand");
1023 if(stat & KMMCStatErrComCRCError) Kern::Printf(" | KMMCStatErrComCRCError");
1024 if(stat & KMMCStatErrLockUnlock) Kern::Printf(" | KMMCStatErrLockUnlock");
1025 if(stat & KMMCStatCardIsLocked) Kern::Printf(" | KMMCStatCardIsLocked");
1026 if(stat & KMMCStatErrWPViolation) Kern::Printf(" | KMMCStatErrWPViolation");
1027 if(stat & KMMCStatErrEraseParam) Kern::Printf(" | KMMCStatErrEraseParam");
1028 if(stat & KMMCStatErrEraseSeqError) Kern::Printf(" | KMMCStatErrEraseSeqError");
1029 if(stat & KMMCStatErrBlockLenError) Kern::Printf(" | KMMCStatErrBlockLenError");
1030 if(stat & KMMCStatErrAddressError) Kern::Printf(" | KMMCStatErrAddressError");
1031 if(stat & KMMCStatErrOutOfRange) Kern::Printf(" | KMMCStatErrOutOfRange");
1034 Kern::Printf(" -----------------------------------------------");
1037 // -------- class TMMCRCAPool --------
1039 TRCA TMMCRCAPool::GetFreeRCA()
1041 * Returns a free RCA number from the pool or zero if none is available
1044 OstTraceFunctionEntry1( TMMCRCAPOOL_GETFREERCA_ENTRY, this );
1045 TUint32 seekm = (iPool | iLocked) + 1;
1046 iPool |= (seekm & ~iLocked);
1049 if( (seekm & 0xFFFFFFFF) == 0 )
1052 OstTraceFunctionExitExt( TMMCRCAPOOL_GETFREERCA_EXIT1, this, (TUint) ret);
1058 if ((seekm & 0xFFFF) == 0) { seekm >>= 16; pos = 17; }
1059 if ((seekm & 0xFF) == 0) { seekm >>= 8; pos += 8; }
1060 if ((seekm & 0xF) == 0) { seekm >>= 4; pos += 4; }
1061 if ((seekm & 0x3) == 0) { seekm >>= 2; pos += 2; }
1062 if ((seekm & 0x1) == 0) pos++;
1064 // Multiply return value by 257 so that 1 is never returned. (0x0001 is the default RCA value.)
1065 // The RCA integer value is divided by 257 in LockRCA() and UnlockRCA() to compensate
1066 // for this adjustment. These functions are only ever called in this file with the iRCA
1067 // field of a TMMCard object, and not with arbitrary values.
1068 // The iRCA field itself is only assigned values from iNewCards[] or zero. iNewCards
1069 // in turn is fed values from this function, in DMMCStack::CIMUpdateAcqSM() / EStSendCIDIssued.
1071 ret = TUint16(pos << 8 | pos);
1072 OstTraceFunctionExitExt( TMMCRCAPOOL_GETFREERCA_EXIT2, this, (TUint) ret);
1078 // -------- class TMMCSessRing --------
1080 TMMCSessRing::TMMCSessRing()
1084 : iPMark(NULL),iPoint(NULL),iPrevP(NULL),iSize(0)
1085 {OstTraceFunctionEntry1( TMMCSESSRING_TMMCSESSRING_ENTRY, this );}
1088 void TMMCSessRing::Erase()
1090 * Erases all the ring content
1093 OstTraceFunctionEntry1( TMMCSESSRING_ERASE_ENTRY, this );
1094 iPMark = iPoint = iPrevP = NULL; iSize = 0;
1095 OstTraceFunctionExit1( TMMCSESSRING_ERASE_EXIT, this );
1099 DMMCSession* TMMCSessRing::operator++(TInt)
1101 * Post increment of Point
1104 if( iPoint == NULL )
1107 if( (iPrevP=iPoint) == iPMark )
1110 iPoint = iPoint->iLinkP;
1116 TBool TMMCSessRing::Point(DMMCSession* aSessP)
1118 * Finds aSessP and sets Point to that position
1121 OstTraceFunctionEntryExt( TMMCSESSRING_POINT_ENTRY, this );
1124 while( iPoint != NULL )
1125 if( iPoint == aSessP )
1127 OstTraceFunctionExitExt( TMMCSESSRING_POINT_EXIT1, this, (TUint) ETrue );
1131 this->operator++(0);
1133 OstTraceFunctionExitExt( TMMCSESSRING_POINT_EXIT2, this, (TUint) EFalse );
1137 void TMMCSessRing::Add(DMMCSession* aSessP)
1139 * Inserts aSessP before Marker. Point is moved into the Marker position.
1142 OstTraceFunctionEntryExt( TMMCSESSRING_ADD1_ENTRY, this );
1145 iPMark = iPrevP = iPoint = aSessP;
1146 aSessP->iLinkP = aSessP;
1148 OstTraceFunctionExit1( TMMCSESSRING_ADD1_EXIT1, this );
1152 iPoint = iPMark->iLinkP;
1153 iPMark->iLinkP = aSessP;
1154 aSessP->iLinkP = iPoint;
1155 iPMark = iPrevP = aSessP;
1157 OstTraceFunctionExit1( TMMCSESSRING_ADD1_EXIT2, this );
1161 void TMMCSessRing::Add(TMMCSessRing& aRing)
1163 * Inserts aRing before Marker. Point is moved into the Marker position.
1164 * aRing Marker becomes the fisrt inserted element.
1168 OstTraceFunctionEntry1( TMMCSESSRING_ADD2_ENTRY, this );
1171 if( aRing.iSize == 0 )
1173 OstTraceFunctionExit1( TMMCSESSRING_ADD2_EXIT1, this );
1179 iPrevP = iPMark = aRing.iPMark;
1180 iPoint = iPrevP->iLinkP;
1181 iSize = aRing.iSize;
1185 iPrevP->iLinkP = aRing.iPMark->iLinkP;
1186 iPMark = iPrevP = aRing.iPMark;
1187 iPrevP->iLinkP = iPoint;
1188 iSize += aRing.iSize;
1192 OstTraceFunctionExit1( TMMCSESSRING_ADD2_EXIT2, this );
1195 DMMCSession* TMMCSessRing::Remove()
1197 * Removes an element pointed to by Point.
1198 * Point (and possibly Marker) move forward as in operator++
1201 OstTraceFunctionEntry1( TMMCSESSRING_REMOVE1_ENTRY, this );
1202 DMMCSession* remS = iPrevP;
1208 remS = remS->iLinkP;
1209 iPrevP->iLinkP = remS->iLinkP;
1212 if( iPoint != NULL )
1213 iPoint = iPrevP->iLinkP;
1215 if( iPMark == remS )
1222 OstTraceFunctionExitExt( TMMCSESSRING_REMOVE1_EXIT, this, ( TUint )( remS ) );
1227 void TMMCSessRing::Remove(DMMCSession* aSessP)
1229 * Removes a specified session from the ring
1232 OstTraceFunctionEntryExt( TMMCSESSRING_REMOVE2_ENTRY, this );
1236 DMMCSocket::Panic(DMMCSocket::EMMCSessRingNoSession);
1237 OstTraceFunctionExit1( TMMCSESSRING_REMOVE2_EXIT, this );
1242 // -------- class TMMCStateMachine --------
1246 Removes all state from the state machine.
1248 It also resets the stack and the exit code.
1250 EXPORT_C void TMMCStateMachine::Reset()
1252 OstTraceFunctionEntry1( TMMCSTATEMACHINE_RESET_ENTRY, this );
1254 iSP = 0; iExitCode = 0;
1255 iStack[0].iState = 0; iStack[0].iTrapMask = 0;
1256 OstTraceFunctionExit1( TMMCSTATEMACHINE_RESET_EXIT, this );
1263 The state machine dispatcher.
1265 @return The MultiMediaCard error code.
1267 EXPORT_C TMMCErr TMMCStateMachine::Dispatch()
1269 OstTraceFunctionEntry1( TMMCSTATEMACHINE_DISPATCH_ENTRY, this );
1271 // If a state machine returns non-zero, i.e. a non-empty error set, then the second
1272 // inner while loop is broken. The errors are thrown like an exception where the
1273 // stack is unravelled until it reaches a state machine which can handle at least
1274 // one of the error codes, else this function returns with the exit code or'd with
1275 // KMMCErrBypass. If the state machine returns zero, then this function returns
1276 // zero if iSuspend is set, i.e., if the stack is waiting on an asynchronous event.
1277 // If suspend is not set, then the next state machine is called. This may be the
1278 // same as the current state machine, or its caller if the current state machine
1279 // ended called Pop() before exiting, e.g., via SMF_END.
1281 while( iSP >= 0 && !iAbort )
1283 // If there is an un-trapped error, wind back down the stack, either
1284 // to the end of the stack or until the error becomes trapped.
1285 while( iSP >= 0 && (iExitCode & ~iStack[iSP].iTrapMask) != 0 )
1288 iExitCode &= ~KMMCErrBypass;
1292 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Err %x",iExitCode));
1293 OstTrace1( TRACE_INTERNALS, TMMCSTATEMACHINE_DISPATCH, "iExitCode=0x%x", iExitCode );
1296 while( iSP >= 0 && !iAbort )
1298 __KTRACE_OPT(KPBUS1,Kern::Printf("-msm:dsp:%02x:%08x.%02x",iSP, TUint32(iStack[iSP].iFunction), State()));
1299 OstTraceExt3( TRACE_INTERNALS, TMMCSTATEMACHINE_DISPATCH2, "iSP=%d; iStack[iSP].iFunction=0x%08x; State=0x%02x", (TInt) iSP, (TUint) iStack[iSP].iFunction, (TUint) State() );
1302 const TMMCErr signal = iStack[iSP].iFunction(iContextP);
1312 __KTRACE_OPT(KPBUS1,Kern::Printf("<msm:dsp:exitslp"));
1313 OstTraceFunctionExit1( TMMCSTATEMACHINE_DISPATCH_EXIT1, this );
1319 __KTRACE_OPT(KPBUS1,Kern::Printf("<msm:dsp:exit%08x", iExitCode));
1320 OstTraceFunctionExit1( TMMCSTATEMACHINE_DISPATCH_EXIT2, this );
1321 return( KMMCErrBypass | iExitCode );
1328 Pushes another state machine entry onto the stack.
1330 Typically, this is invoked using one of the macros:
1331 SMF_CALL, SMF_CALLWAIT, SMF_INVOKES, SMF_INVOKEWAITS
1333 @param anEntry The state machine function to be run; this will start at
1334 the initial state (EStBegin), with no exception handling defined.
1335 @param aSuspend Indicates whether the state machine is to block on return to the dispatcher;
1336 Specify ETrue to block; EFalse not to block.
1337 EFalse is the default, if not explicitly stated.
1341 @panic PBUS-MMC 0 if the maximum depth of nested state machine entries is being exeeded.
1346 @see SMF_INVOKEWAITS
1348 EXPORT_C TMMCErr TMMCStateMachine::Push(TMMCErr (*anEntry)(TAny*), TBool aSuspend)
1350 OstTraceFunctionEntry1( TMMCSTATEMACHINE_PUSH_ENTRY, this );
1352 __ASSERT_ALWAYS(TUint(iSP)<KMaxMMCMachineStackDepth,
1353 DMMCSocket::Panic(DMMCSocket::EMMCMachineStack));
1354 iStack[iSP].iFunction = anEntry;
1355 iStack[iSP].iState = 0;
1356 iStack[iSP].iTrapMask = 0;
1359 OstTraceFunctionExit1( TMMCSTATEMACHINE_PUSH_EXIT, this );
1367 Jumps to the specified state machine function in the current state machine entry.
1369 @param anEntry The state machine function to be run; this will start at
1370 the initial state (EStBegin), with no exception handling defined.
1371 @param aSuspend Indicates whether the state machine is to block on return to the dispatcher;
1372 Specify ETrue to block; EFalse not to block.
1373 EFalse is the default, if not explicitly stated.
1377 EXPORT_C TMMCErr TMMCStateMachine::Jump(TMMCErr (*anEntry)(TAny*), TBool aSuspend)
1379 OstTraceFunctionEntry1( TMMCSTATEMACHINE_JUMP_ENTRY, this );
1380 iStack[iSP].iFunction = anEntry;
1381 iStack[iSP].iState = 0;
1382 iStack[iSP].iTrapMask = 0;
1385 OstTraceFunctionExit1( TMMCSTATEMACHINE_JUMP_EXIT, this );
1392 // -------- class DMMCStack --------
1394 #pragma warning( disable : 4355 ) // this used in initializer list
1395 EXPORT_C DMMCStack::DMMCStack(TInt /*aBus*/, DMMCSocket* aSocket)
1397 * Constructs a DMMCStack object
1398 * @param aBus Unused
1399 * @param aSocket A pointer to the associated socket.
1404 iStackDFC(DMMCStack::StackDFC, this, 1),
1405 iSelectedCard(TUint16(~0)),
1407 iStackSession(NULL),
1408 iAutoUnlockSession(TMMCCallBack(AutoUnlockCBST, this)),
1409 iInitState(EISPending),
1417 // iLockingSessionP(NULL),
1418 // iAttention(EFalse),
1419 // iAbortReq(EFalse),
1420 // iCompReq(EFalse),
1421 // iDoorOpened(EFalse),
1422 // iPoweredUp(EFalse),
1423 // iDFCRunning(EFalse),
1424 // iAbortAll(EFalse),
1427 // iCurrentOpRange(0),
1428 // iCardsPresent(0),
1429 // iMaxCardsInStack(0)
1431 #pragma warning( default : 4355 )
1433 EXPORT_C TInt DMMCStack::Init()
1435 * Initialises the generic MMC stack.
1436 * @return KErrNone if successful, standard error code otherwise.
1439 OstTraceFunctionEntry1( DMMCSTACK_INIT_ENTRY, this );
1440 // allocate and initialize session object
1441 if ((iStackSession = AllocSession(TMMCCallBack(StackSessionCBST, this))) == 0)
1443 OstTraceFunctionExitExt( DMMCSTACK_INIT_EXIT1, this, KErrNoMemory );
1444 return KErrNoMemory;
1447 // create helper class
1448 if ((iBody = new DBody(*this)) == NULL)
1450 OstTraceFunctionExitExt( DMMCSTACK_INIT_EXIT2, this, KErrNoMemory );
1451 return KErrNoMemory;
1454 iStackSession->SetStack(this);
1456 iStackDFC.SetDfcQ(&iSocket->iDfcQ);
1458 // Get the maximal number of cards from ASSP layer
1459 iMaxCardsInStack = iSocket->TotalSupportedCards();
1460 if ( iMaxCardsInStack > KMaxMMCardsPerStack )
1461 iMaxCardsInStack=KMaxMMCardsPerStack;
1463 TInt r = iCardArray->AllocCards();
1465 OstTraceFunctionExitExt( DMMCSTACK_INIT_EXIT3, this, r );
1469 EXPORT_C void DMMCStack::PowerUpStack()
1471 * Enforce stack power-up and initialisation.
1472 * This is an asynchronous operation, which calls DMMCSocket::PowerUpSequenceComplete upon completion.
1475 OstTraceFunctionEntry1( DMMCSTACK_POWERUPSTACK_ENTRY, this );
1476 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:pus"));
1478 if (iPSLBuf == NULL)
1480 GetBufferInfo(&iPSLBuf, &iPSLBufLen);
1481 iMinorBufLen = KMinMinorBufSize;
1484 ReportPowerDown(); // ensure power will be switch on regardless
1486 Scheduler( iInitialise );
1487 OstTraceFunctionExit1( DMMCSTACK_POWERUPSTACK_EXIT, this );
1490 void DMMCStack::QSleepStack()
1492 * Schedules a session to place media in Sleep State
1495 OstTraceFunctionEntry1( DMMCSTACK_QSLEEPSTACK_ENTRY, this );
1496 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:qsleep"));
1498 Scheduler( iSleep );
1499 OstTraceFunctionExit1( DMMCSTACK_QSLEEPSTACK_EXIT, this );
1502 EXPORT_C void DMMCStack::PowerDownStack()
1504 * Enforce stack power down.
1505 * Clients generally shouldn't need to concern themselves with powering down a stack
1506 * unless they specifically need to perform a power reset of a card. If a driver fails to
1507 * open then normal practise is for that driver to leave the card powered so that any subsequent
1508 * driver which may attempt to open immediately after this failed attempt won't have to re-power the card.
1509 * If no driver successfully opens on the card then the Controllers inactivity/not in use
1510 * timeout system can be left to power it down.
1513 OstTraceFunctionEntry1( DMMCSTACK_POWERDOWNSTACK_ENTRY, this );
1514 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:pds"));
1517 iInitState = EISPending;
1520 TBool cardRemoved = (iStackState & KMMCStackStateCardRemoved);
1521 for (TUint i=0;i<iMaxCardsInStack;i++)
1523 TMMCard& card = iCardArray->Card(i);
1524 card.SetBusWidth(1);
1525 card.SetHighSpeedClock(0);
1528 iCardArray->DeclareCardAsGone(i);
1532 // set the locked bit if the card has a password - need to do this
1533 // now that RLocalDrive::Caps() no longer powers up the stack
1534 if (card.HasPassword())
1536 TMapping* pmp = iSocket->iPasswordStore->FindMappingInStore(card.CID());
1537 if (!pmp || pmp->iState != TMapping::EStValid)
1539 *((TUint32*) &card.iStatus) |= KMMCStatCardIsLocked;
1543 // Remove card state flags, after a power cycle all cards are in idle state
1544 *((TUint32*) &card.iStatus) &= ~KMMCStatCurrentStateMask;
1548 iStackState &= ~KMMCStackStateCardRemoved;
1551 iSocket->iVcc->SetState(EPsuOff);
1552 if (iSocket->iVccCore)
1553 iSocket->iVccCore->SetState(EPsuOff);
1555 // Cancel timers, reset ASSP, cancel stack DFC & remove session from workset
1556 // to ensure stack doesn't wake up again & attempt to dereference iSessionP
1562 // The stack may have powered down while attempting to power up (e.g. because a card has not responded),
1563 // so ensure stack doesn't attempt to initialize itself again until next PowerUpStack()
1564 iInitialise = EFalse;
1565 iStackState &= ~(KMMCStackStateInitInProgress | KMMCStackStateInitPending | KMMCStackStateBusInconsistent | KMMCStackStateWaitingDFC);
1567 OstTraceFunctionExit1( DMMCSTACK_POWERDOWNSTACK_EXIT, this );
1571 // DMMCStack:: --- Stack Scheduler and its supplementary functions ---
1573 DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedGetOnDFC()
1575 * Initiates stack DFC. Returns either Continue or Loop.
1578 OstTraceFunctionEntry1( DMMCSTACK_SCHEDGETONDFC_ENTRY, this );
1579 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sgd"));
1583 OstTraceFunctionExitExt( DMMCSTACK_SCHEDGETONDFC_EXIT1, this, (TInt) ESchedContinue);
1584 return ESchedContinue;
1587 if( (iStackState & KMMCStackStateWaitingDFC) == 0 )
1589 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sgd:q"));
1590 iStackState |= KMMCStackStateWaitingDFC;
1591 if (NKern::CurrentContext()==NKern::EInterrupt)
1597 OstTraceFunctionExitExt( DMMCSTACK_SCHEDGETONDFC_EXIT2, this, (TInt) ESchedLoop);
1601 void DMMCStack::SchedSetContext(DMMCSession* aSessP)
1603 * Sets up the specified session as the current session.
1604 * Invoked by JobChooser and Initialiser.
1605 * @param aSessP A pointer to the session.
1608 OstTraceFunctionEntry1( DMMCSTACK_SCHEDSETCONTEXT_ENTRY, this );
1609 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ssc"));
1611 if( (iStackState & (KMMCStackStateInitPending|KMMCStackStateBusInconsistent)) != 0 &&
1612 aSessP->iSessionID != ECIMInitStack )
1614 iInitialise = ETrue;
1615 OstTraceFunctionExit1( DMMCSTACK_SCHEDSETCONTEXT_EXIT1, this );
1619 if( iSessionP != aSessP )
1621 iStackState |= KMMCStackStateReScheduled;
1622 MergeConfig( aSessP );
1624 if( aSessP->iSessionID == ECIMInitStack )
1625 iInitialise = ETrue;
1627 if( InitStackInProgress() )
1628 MarkComplete( aSessP, KMMCErrStackNotReady );
1630 if( aSessP->iBrokenLock )
1631 MarkComplete( aSessP, KMMCErrBrokenLock );
1636 iSessionP->iState &= ~KMMCSessStateDoReSchedule;
1637 OstTraceFunctionExit1( DMMCSTACK_SCHEDSETCONTEXT_EXIT2, this );
1640 void DMMCStack::SchedDoAbort(DMMCSession* aSessP)
1642 * Aborts asynchronous activities of a session aSessP
1643 * @param aSessP A pointer to the session to be aborted.
1646 OstTraceFunctionEntryExt( DMMCSTACK_SCHEDDOABORT_ENTRY, this );
1647 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sda"));
1650 if( aSessP->iBlockOn & KMMCBlockOnPollTimer )
1651 aSessP->iPollTimer.Cancel();
1653 if( aSessP->iBlockOn & KMMCBlockOnRetryTimer )
1654 aSessP->iRetryTimer.Cancel();
1656 if( aSessP->iBlockOn & KMMCBlockOnPgmTimer )
1657 aSessP->iProgramTimer.Cancel();
1658 #endif // #ifdef __EPOC32__
1660 if( aSessP->iBlockOn & KMMCBlockOnWaitToLock )
1661 iStackState &= ~KMMCStackStateWaitingToLock;
1663 if( aSessP->iBlockOn & (KMMCBlockOnASSPFunction | KMMCBlockOnInterrupt | KMMCBlockOnDataTransfer) )
1666 if( (aSessP->iState & (KMMCSessStateInProgress|KMMCSessStateCritical)) ==
1667 (KMMCSessStateInProgress|KMMCSessStateCritical) )
1668 iStackState |= KMMCStackStateInitPending;
1671 (void)__e32_atomic_and_ord32(&aSessP->iBlockOn, ~(KMMCBlockOnPollTimer | KMMCBlockOnRetryTimer |
1672 KMMCBlockOnWaitToLock | KMMCBlockOnASSPFunction |
1673 KMMCBlockOnInterrupt | KMMCBlockOnDataTransfer) );
1674 OstTraceFunctionExit1( DMMCSTACK_SCHEDDOABORT_EXIT, this );
1677 DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedResolveStatBlocks(DMMCSession* aSessP)
1679 * Checks static blocking conditions and removes them as necessary
1680 * @param aSessP A pointer to the session.
1681 * @return EschedContinue or ESchedLoop (if scheduler is to be restarted)
1684 OstTraceFunctionEntryExt( DMMCSTACK_SCHEDRESOLVESTATBLOCKS_ENTRY, this );
1686 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:srsb"));
1688 if( (aSessP->iBlockOn & KMMCBlockOnCardInUse) && aSessP->iCardP->iUsingSessionP == NULL )
1689 aSessP->SynchUnBlock( KMMCBlockOnCardInUse );
1691 if( (aSessP->iBlockOn & KMMCBlockOnWaitToLock) && iWorkSet.Size() == 1 )
1693 // ECIMLockStack processed here
1694 iLockingSessionP = aSessP; // in this order
1695 iStackState &= ~KMMCStackStateWaitingToLock;
1696 aSessP->SynchUnBlock( KMMCBlockOnWaitToLock );
1697 MarkComplete( aSessP, KMMCErrNone );
1698 OstTraceFunctionExitExt( DMMCSTACK_SCHEDRESOLVESTATBLOCKS_EXIT1, this, (TInt) ESchedLoop );
1702 OstTraceFunctionExitExt( DMMCSTACK_SCHEDRESOLVESTATBLOCKS_EXIT2, this, (TInt) ESchedContinue );
1703 return ESchedContinue;
1706 DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedGroundDown(DMMCSession* aSessP, TMMCErr aReason)
1708 * Aborts all asynchronous activities of session aSessP with
1709 * iExitCode = aReason. This function conserns itself with asynchronous
1710 * activities only; session static state (eg Critical) is not taken into
1711 * account. Session dynamic state and action flags (i.e. SafeInGaps,
1712 * DoReSchedule and DoDFC) are cleared.
1713 * @param aSessP A pointer to the session.
1714 * @param aReason The reason for aborting.
1715 * @return EschedContinue if everything's done OK.
1716 * @return ESchedLoop if the session can not be safely grounded (eg
1717 * iStackSession) and should therefore be aborted and/or completed by a
1718 * separate scheduler pass.
1721 OstTraceExt3(TRACE_FLOW, DMMCSTACK_SCHEDGROUNDDOWN_ENTRY, "DMMCStack::SchedGroundDown;aSessionP=%x;aReason=%d;this=%x", (TUint) aSessP, (TInt) aReason, (TUint) this);
1722 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sgdn"));
1724 if( (aSessP == iStackSession) || InitStackInProgress() )
1726 OstTraceFunctionExitExt( DMMCSTACK_SCHEDGROUNDDOWN_EXIT1, this, (TInt) ESchedLoop );
1730 if( aSessP->iState & KMMCSessStateInProgress )
1732 SchedDoAbort( aSessP );
1733 //coverity[check_return]
1734 //return value is not saved or checked because there is no further uses.
1735 aSessP->iMachine.SetExitCode( aReason );
1736 aSessP->iState &= ~(KMMCSessStateSafeInGaps | KMMCSessStateDoReSchedule |
1737 KMMCSessStateDoDFC);
1740 OstTraceFunctionExitExt( DMMCSTACK_SCHEDGROUNDDOWN_EXIT2, this, (TInt) ESchedContinue );
1741 return ESchedContinue;
1744 DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedEnqueStackSession(TMMCSessionTypeEnum aSessID)
1746 * Prepare internal session for InitStack and enque it into WorkSet.
1747 * @return EschedContinue or ESchedLoop
1750 OstTraceExt2(TRACE_FLOW, DMMCSTACK_SCHEDENQUESTACKSESSION_ENTRY ,"DMMCStack::SchedEnqueStackSession;aSessID=%d;this=%x", (TInt) aSessID, (TUint) this);
1751 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sess"));
1753 if( iStackSession->IsEngaged() )
1755 MarkComplete( iStackSession, KMMCErrAbort );
1756 OstTraceFunctionExitExt( DMMCSTACK_SCHEDENQUESTACKSESSION_EXIT1, this, (TInt) ESchedLoop );
1760 iStackSession->SetupCIMControl( aSessID );
1761 iWorkSet.Add( iStackSession );
1762 iStackSession->iState |= KMMCSessStateEngaged;
1763 OstTraceFunctionExitExt( DMMCSTACK_SCHEDENQUESTACKSESSION_EXIT2, this, (TInt) ESchedContinue );
1764 return ESchedContinue;
1767 void DMMCStack::SchedGrabEntries()
1769 * Merges Entry queue into Ready queue. Invoked at the scheduler entry and
1770 * after the completion pass
1773 OstTraceFunctionEntry1( DMMCSTACK_SCHEDGRABENTRIES_ENTRY, this );
1775 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sge"));
1777 iAttention = EFalse; // Strictly in this order
1778 if( !iEntryQueue.IsEmpty() )
1781 iReadyQueue.Add( iEntryQueue );
1784 OstTraceFunctionExit1( DMMCSTACK_SCHEDGRABENTRIES_EXIT, this );
1787 void DMMCStack::SchedDisengage()
1789 * This function is called by AbortPass() and CompletionPass() to remove the session
1790 * at WorkSet Point, to abort its asynchronous activities (if any) and
1791 * clear up the dependent resources
1794 OstTraceFunctionEntry1( DMMCSTACK_SCHEDDISENGAGE_ENTRY, this );
1795 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sd"));
1797 DMMCSession* sessP = iWorkSet.Remove();
1799 SchedDoAbort( sessP );
1801 if( sessP == iSessionP )
1804 if( sessP->iCardP != NULL && sessP->iCardP->iUsingSessionP == sessP )
1805 sessP->iCardP->iUsingSessionP = NULL;
1807 // iAutoUnlockSession may attach to more than once card, so need to iterate
1808 // through all cards and clear their session pointers if they match sessP
1809 if (sessP == &iAutoUnlockSession)
1811 for (TUint i = 0; i < iMaxCardsInStack; i++)
1813 TMMCard& cd = *(iCardArray->CardP(i));
1814 if (cd.iUsingSessionP == sessP)
1815 cd.iUsingSessionP = NULL;
1819 if( sessP->iState & KMMCSessStateASSPEngaged )
1823 OstTraceFunctionExit1( DMMCSTACK_SCHEDDISENGAGE_EXIT, this );
1826 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedAbortPass()
1828 * DMMCStack Scheduler private inline functions. These functions were separated as inline functions
1829 * only for the sake of Scheduler() clarity.
1832 OstTraceFunctionEntry1( DMMCSTACK_SCHEDABORTPASS_ENTRY, this );
1833 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sap"));
1841 while( (sessP = iWorkSet) != NULL )
1842 if( iAbortAll || sessP->iDoAbort )
1847 iReadyQueue.Point();
1849 while( (sessP = iReadyQueue) != NULL )
1850 if( iAbortAll || sessP->iDoAbort )
1852 iReadyQueue.Remove();
1860 OstTraceFunctionExitExt( DMMCSTACK_SCHEDABORTPASS_EXIT1, this, (TInt) ESchedLoop );
1864 // Clearing iAbortAll here is a bit dodgy. It wouldn't work if somebody interrupted us
1865 // at this point, enqued a session and then immediately called Reset() - that session
1866 // would not be discarded. However, the correct solution (enque Reset() requests
1867 // and process them in the Scheduler main loop) seems to be too expensive just to avoid
1868 // this particular effect.
1870 OstTraceFunctionExitExt( DMMCSTACK_SCHEDABORTPASS_EXIT2, this, (TInt) ESchedContinue );
1871 return ESchedContinue;
1874 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedCompletionPass()
1876 * This function calls back all the sessions waiting to be completed
1877 * Returns either Continue or Loop.
1880 OstTraceFunctionEntry1( DMMCSTACK_SCHEDCOMPLETIONPASS_ENTRY, this );
1881 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:scp"));
1886 if( iCompleteAllExitCode )
1889 iWorkSet.Add( iReadyQueue );
1894 while( (sessP = iWorkSet) != NULL )
1895 if( iCompleteAllExitCode || sessP->iDoComplete )
1897 if( (EffectiveModes(sessP->iConfig) & KMMCModeCompleteInStackDFC) != 0 &&
1900 // DFC has been queued so return back to main loop. Next time
1901 // SchedGetOnDfc() will return EFalse, and the callback will be called.
1903 OstTraceFunctionExitExt( DMMCSTACK_SCHEDCOMPLETIONPASS_EXIT1, this, (TInt) ESchedLoop );
1907 SchedDisengage(); // calls iWorkSet.Remove
1908 sessP->iMMCExitCode |= iCompleteAllExitCode;
1909 // Update the controller store if a password operation was in progress.
1910 TBool doCallback = ETrue;
1911 if (sessP->iSessionID == ECIMLockUnlock)
1913 iSocket->PasswordControlEnd(sessP, sessP->EpocErrorCode());
1915 if(sessP->EpocErrorCode() == KErrNone)
1917 sessP->SetupCIMInitStackAfterUnlock();
1918 if(sessP->Engage() == KErrNone)
1920 doCallback = EFalse;
1925 if(sessP->iSessionID == ECIMInitStackAfterUnlock)
1927 // After unlocking the stack, cards may have switched into HS mode
1928 // (HS switch commands are only valid when the card is unlocked).
1930 // Therefore, we need to re-negotiate the maximum bus clock again.
1932 // The PSL will use this to set the master config (limiting the clock if
1935 // Note that the clock may change when a specific card is selected.
1938 iCardArray->UpdateAcquisitions(&maxClk);
1939 SetBusConfigDefaults( iMasterConfig.iBusConfig, maxClk );
1945 // call media driver completion routine or StackSessionCBST().
1946 sessP->iCallBack.CallBack();
1954 OstTraceFunctionExitExt( DMMCSTACK_SCHEDCOMPLETIONPASS_EXIT2, this, (TInt) ESchedLoop );
1958 iCompleteAllExitCode = 0;
1960 OstTraceFunctionExitExt( DMMCSTACK_SCHEDCOMPLETIONPASS_EXIT3, this, ( TInt) ESchedContinue );
1961 return ESchedContinue;
1964 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedInitStack()
1966 * "Immediate" InitStack initiator. Returns either Continue or Loop.
1969 OstTraceFunctionEntry1( DMMCSTACK_SCHEDINITSTACK_ENTRY, this );
1970 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sis"));
1972 if( SchedGetOnDFC() )
1974 OstTraceFunctionExitExt( DMMCSTACK_SCHEDINITSTACK_EXIT1, this, (TInt) ESchedLoop );
1978 if( iSessionP != NULL && (iStackState & KMMCStackStateJobChooser) == 0 )
1980 if( (iSessionP->iState & KMMCSessStateInProgress) )
1982 if( SchedGroundDown(iSessionP, KMMCErrPowerDown) )
1984 MarkComplete( iSessionP, KMMCErrPowerDown );
1985 OstTraceFunctionExitExt( DMMCSTACK_SCHEDINITSTACK_EXIT2, this, (TInt) ESchedLoop );
1990 iSessionP->iMachine.Reset();
1993 // NB if the current session was InitStack InProgress, JobChooser can not be active;
1994 // so we are not going to continue another InitStack as if nothing happened.
1996 iStackState &= ~(KMMCStackStateInitInProgress|KMMCStackStateInitPending);
1998 // If there is no current session (e.g. called from PowerUpStack()) or the current
1999 // session isn't specifically ECIMInitStack (which it rarely will be) then we have to use
2000 // the stack session to perform the stack init.
2001 if( iSessionP == NULL || iSessionP->iSessionID != ECIMInitStack )
2003 if( SchedEnqueStackSession(ECIMInitStack) )
2005 OstTraceFunctionExitExt( DMMCSTACK_SCHEDINITSTACK_EXIT3, this, (TInt) ESchedLoop );
2009 SchedSetContext( iStackSession ); // make the internal session to be current job
2012 // Neither client nor internal session could be blocked here, not even on "BrokenLock"
2013 __ASSERT_ALWAYS( (iSessionP->iBlockOn)==0,
2014 DMMCSocket::Panic(DMMCSocket::EMMCInitStackBlocked) );
2016 iStackState |= KMMCStackStateInitInProgress;
2017 // nothing can stop this session now; it's safe to clear iInitialise here.
2018 iInitialise = EFalse;
2019 OstTraceFunctionExitExt( DMMCSTACK_SCHEDINITSTACK_EXIT4, this, (TInt) ESchedContinue );
2020 return ESchedContinue;
2023 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedSleepStack()
2025 * "Immediate" Stack sleep mode. Returns either Continue or Loop.
2028 OstTraceFunctionEntry1( DMMCSTACK_SCHEDSLEEPSTACK_ENTRY, this );
2029 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:SchdSlp!"));
2031 // Make sure Stack DFC is Running!
2032 if( SchedGetOnDFC() )
2034 __KTRACE_OPT(KPBUS1, Kern::Printf("mst:SchdSlp - DFC not running"));
2035 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSLEEPSTACK_EXIT1, this, (TInt) ESchedLoop );
2039 if( iSessionP != NULL && (iStackState & KMMCStackStateJobChooser) == 0 )
2041 if( (iSessionP->iState & KMMCSessStateInProgress) )
2043 // A session has been queued before sleep,
2044 // cancel sleep and loop for next session
2046 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSLEEPSTACK_EXIT2, this, (TInt) ESchedLoop );
2051 // Use the stack session to perform the stack sleep.
2052 if( SchedEnqueStackSession(ECIMSleep) )
2054 __KTRACE_OPT(KPBUS1,Kern::Printf("SchdSlp: already Enqued"));
2055 // Stack already busy cancel sleep
2057 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSLEEPSTACK_EXIT3, this, (TInt) ESchedLoop );
2061 SchedSetContext( iStackSession ); // make the internal session to be current job
2063 // Sleep has now been queued
2065 iStackState |= KMMCStackStateSleepinProgress;
2066 __KTRACE_OPT(KPBUS1, Kern::Printf("<mst:SchdSlp"));
2068 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSLEEPSTACK_EXIT4, this, (TInt) ESchedLoop );
2073 inline TBool DMMCStack::SchedPreemptable()
2075 * Checks if the current session can be preempted
2077 { // strictly in the following order
2078 OstTraceFunctionEntry1( DMMCSTACK_SCHEDPREEMPTABLE_ENTRY, this );
2079 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:spe"));
2081 if( (iStackState & KMMCStackStateJobChooser) ||
2082 (iSessionP->iState & KMMCSessStateDoReSchedule) )
2084 OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT1, this, (TUint) ETrue );
2088 if( (iSessionP->iBlockOn & KMMCBlockOnASSPFunction) )
2090 OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT2, this, (TUint) EFalse );
2094 TBool preemptDC = EFalse;
2096 if (iSessionP->iBlockOn & KMMCBlockOnYielding)
2098 // Added to support yielding the stack for a specific command.
2101 else if( (iSessionP->iBlockOn & KMMCBlockOnDataTransfer) )
2103 // Added for SDIO Read/Wait and SDC support. This condition
2104 // is set at the variant, and determines whether commands may be
2105 // issued during the data transfer period.
2106 if(!(iSessionP->iState & KMMCSessStateAllowDirectCommands))
2108 OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT3, this, (TUint) EFalse );
2112 // We must consider the remaining blocking conditions
2113 // before being sure that we can enable pre-emtion of this session
2117 if( (iSessionP->iBlockOn & (KMMCBlockOnCardInUse | KMMCBlockOnNoRun)) )
2119 OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT4, this, (TUint) ETrue );
2123 if( (iConfig.iModes & KMMCModeEnablePreemption) == 0 )
2125 OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT5, this, (TUint) EFalse );
2129 if( (iSessionP->iBlockOn & KMMCBlockOnGapTimersMask) &&
2130 (iConfig.iModes & KMMCModePreemptInGaps) &&
2131 (iSessionP->iState & KMMCSessStateSafeInGaps) )
2133 OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT6, this, (TUint) ETrue );
2137 if( iSessionP->iBlockOn & KMMCBlockOnInterrupt )
2139 OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT7, this, (TUint) ETrue );
2145 OstTraceFunctionExitExt( DDMMCSTACK_SCHEDPREEMPTABLE_EXIT8, this, (TUint) ETrue );
2149 OstTraceFunctionExitExt( DMMCSTACK_SCHEDPREEMPTABLE_EXIT9, this, (TUint) EFalse );
2153 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedSession()
2155 * Current context analyser. Returns Exit, Loop or ChooseJob.
2158 OstTraceFunctionEntry1( DMMCSTACK_SCHEDSESSION_ENTRY, this );
2160 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ss"));
2162 // If no current session selected then we need to choose one
2163 if (iSessionP == NULL)
2165 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT1, this, (TInt) ESchedChooseJob );
2166 return ESchedChooseJob;
2169 // Check any static blocking conditions on the current session and remove if possible
2170 if (SchedResolveStatBlocks(iSessionP)==ESchedLoop)
2172 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT2, this, (TInt) ESchedLoop );
2176 // If current session is still blocked, see if we could pre-empt the session
2177 if (iSessionP->iBlockOn)
2179 if( SchedPreemptable() )
2181 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT3, this, (TInt) ESchedChooseJob );
2182 return ESchedChooseJob;
2185 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT4, this, (TInt) ESchedExit );
2186 return ESchedExit; // No preemption possible
2189 // If the current session has been marked to be 'un-scheduled' then we
2190 // need to choose another session if ones available
2191 if ( (iSessionP->iState & KMMCSessStateDoReSchedule) )
2193 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT5, this, (TInt) ESchedChooseJob );
2194 return ESchedChooseJob;
2197 // Check if this session requires to be run in DFC context - loop if necessary
2198 if ( (iSessionP->iState & KMMCSessStateDoDFC) )
2200 iSessionP->iState &= ~KMMCSessStateDoDFC;
2201 if( SchedGetOnDFC()==ESchedLoop )
2203 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT6, this, (TInt) ESchedLoop );
2208 // Now we actually execute the current session
2209 if( iLockingSessionP != NULL )
2211 if( (iStackState & KMMCStackStateLocked) )
2213 if( iSessionP != iLockingSessionP )
2215 iLockingSessionP->iBrokenLock = ETrue;
2216 iLockingSessionP = NULL;
2217 DeselectsToIssue(KMMCIdleCommandsAtRestart); // use it for the number of deselects as well
2221 if( iSessionP == iLockingSessionP )
2222 iStackState |= KMMCStackStateLocked;
2225 if( iSessionP->iInitContext != iInitContext )
2227 // If the current session's init_stack pass number is set but isn't the same as the current
2228 // pass number, it indicates this session is being resumed having tried to recover from
2229 // a bus inconsitency by re-initialising the stack. Set the exit code to a special
2230 // value so this session can un-wind from where the initial error occured, back to the start.
2231 if( iSessionP->iInitContext != 0 )
2232 //coverity[check_return]
2233 //return value is not saved or checked because there is no further uses.
2234 iSessionP->iMachine.SetExitCode(KMMCErrInitContext | iSessionP->iMachine.ExitCode());
2236 iSessionP->iInitContext = iInitContext;
2239 iStackState &= ~KMMCStackStateJobChooser;
2240 iSessionP->iState &= ~KMMCSessStateSafeInGaps;
2242 // Execute the session state machine until it completes, is blocked or is aborted.
2243 TMMCErr exitCode = iSessionP->iMachine.Dispatch();
2245 iStackState &= ~KMMCStackStateReScheduled;
2248 MarkComplete( iSessionP, (exitCode & ~KMMCErrBypass) );
2250 OstTraceFunctionExitExt( DMMCSTACK_SCHEDSESSION_EXIT7, this, (TInt) ESchedLoop );
2254 TBool DMMCStack::SchedYielding(DMMCSession* aSessP)
2256 * Check whether the scheduler should yield to another command
2259 OstTraceFunctionEntryExt( DMMCSTACK_SCHEDYIELDING_ENTRY, this );
2260 // Test whether a full loop through the sessions has occurred during a yield
2261 if ((aSessP->iBlockOn & KMMCBlockOnYielding) && (iStackState & KMMCStackStateYielding))
2263 // We've looped, now stop yielding
2264 aSessP->iBlockOn &= ~KMMCBlockOnYielding;
2265 iStackState &= ~KMMCStackStateYielding;
2267 TBool ret = (iStackState & KMMCStackStateYielding) != 0;
2268 OstTraceFunctionExitExt( DMMCSTACK_SCHEDYIELDING_EXIT, this, ret );
2272 TBool DMMCStack::SchedAllowDirectCommands(DMMCSession* aSessP)
2274 * Check whether direct only commands can be run.
2277 OstTraceFunctionEntryExt( DMMCSTACK_SCHEDALLOWDIRECTCOMMANDS_ENTRY, this );
2278 TBool allowDirectCommands = EFalse;
2280 // Test the remaining sessions to see if they have a DMA data transfer blockage which allow direct commands only
2281 DMMCSession* testSessP = aSessP;
2284 if ((testSessP->iBlockOn & KMMCBlockOnDataTransfer) && (testSessP->iState & KMMCSessStateAllowDirectCommands))
2285 allowDirectCommands = ETrue;
2286 testSessP = testSessP->iLinkP;
2288 while((aSessP != testSessP) && (testSessP != NULL));
2290 OstTraceFunctionExitExt( DMMCSTACK_SCHEDALLOWDIRECTCOMMANDS_EXIT, this, allowDirectCommands );
2291 return allowDirectCommands;
2294 inline DMMCStack::TMMCStackSchedStateEnum DMMCStack::SchedChooseJob()
2296 * Find an unblocked job to run. Returns Exit or Loop.
2299 OstTraceFunctionEntry1( DMMCSTACK_SCHEDCHOOSEJOB_ENTRY, this );
2300 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:scj"));
2302 iStackState |= KMMCStackStateJobChooser;
2304 DMMCSession* sessP = NULL;
2306 if( iLockingSessionP != NULL ) // if stack is already locked we accept only locking session
2308 if( iWorkSet.IsEmpty() && iReadyQueue.Point(iLockingSessionP) )
2309 sessP = iReadyQueue.Remove();
2311 else // otherwise we might add a fresh session from reserve
2313 iStackState &= ~KMMCStackStateLocked;
2314 if( iWorkSet.Size() < KMMCMaxJobsInStackWorkSet && // if work set is not too big
2315 !iReadyQueue.IsEmpty() && // and there are ready sessions
2316 (iStackState & KMMCStackStateWaitingToLock) == 0 ) // and nobody waits to lock us
2318 iReadyQueue.Point(); // at marker to preserve FIFO
2319 sessP = iReadyQueue.Remove();
2325 iWorkSet.Add( sessP );
2327 if( sessP->iSessionID == ECIMLockStack )
2329 sessP->SynchBlock( KMMCBlockOnWaitToLock | KMMCBlockOnNoRun );
2330 sessP->iBrokenLock = EFalse;
2331 iStackState |= KMMCStackStateWaitingToLock;
2335 if( iSessionP != NULL )
2336 iWorkSet.AdvanceMarker(); // move current session to the end of the queue
2340 while( (sessP = iWorkSet) != NULL )
2342 // first, remove all static blocking conditions
2343 if( SchedResolveStatBlocks(sessP) )
2345 OstTraceFunctionExitExt( DMMCSTACK_SCHEDCHOOSEJOB_EXIT1, this, (TInt) ESchedLoop );
2349 TBool scheduleSession = ETrue;
2350 // Test whether we are yielding
2351 if (SchedYielding(sessP) && (sessP->Command().iSpec.iCommandType != iYieldCommandType))
2352 scheduleSession = EFalse;
2353 // Test whether this session is blocked
2354 else if (sessP->iBlockOn)
2355 scheduleSession = EFalse;
2356 // Test whether we can only handle direct commands
2357 else if (SchedAllowDirectCommands(sessP) && (sessP->Command().iSpec.iCommandType != ECmdTypeADC))
2358 scheduleSession = EFalse;
2360 if (scheduleSession)
2362 iWorkSet.SetMarker();
2363 SchedSetContext( sessP );
2364 OstTraceFunctionExitExt( DMMCSTACK_SCHEDCHOOSEJOB_EXIT2, this, (TInt) ESchedLoop );
2371 OstTraceFunctionExitExt( DMMCSTACK_SCHEDCHOOSEJOB_EXIT3, this, (TInt) ESchedExit );
2375 void DMMCStack::StackDFC(TAny* aStackP)
2377 * This DFC is used to startup Stack Scheduler from the background.
2380 OstTraceFunctionEntry0( DMMCSTACK_STACKDFC_ENTRY );
2381 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sdf"));
2383 DMMCStack* const stackP = static_cast<DMMCStack*>(aStackP);
2384 stackP->Scheduler( stackP->iDFCRunning );
2385 OstTraceFunctionExit0( DMMCSTACK_STACKDFC_EXIT );
2388 void DMMCStack::Scheduler(volatile TBool& aFlag)
2390 * This is the main function which controls, monitors and synchronises session execution.
2391 * It's divided into the entry function Scheduler() and the scheduling mechanism itself,
2395 OstTraceFunctionEntry0( DMMCSTACK_SCHEDULER_ENTRY );
2396 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sch"));
2401 if( iStackState & KMMCStackStateRunning )
2407 iStackState |= KMMCStackStateRunning;
2410 OstTraceFunctionExit0( DMMCSTACK_SCHEDULER_EXIT );
2413 void DMMCStack::DoSchedule()
2415 OstTraceFunctionEntry1( DMMCSTACK_DOSCHEDULE_ENTRY, this );
2416 __KTRACE_OPT(KPBUS1,Kern::Printf(">mst:dos"));
2422 if( iAbortReq && SchedAbortPass() )
2426 iStackState &= ~KMMCStackStateWaitingDFC;
2428 if( iStackState & KMMCStackStateWaitingDFC )
2431 if( iCompReq && SchedCompletionPass() )
2434 if( iInitialise && SchedInitStack() )
2437 if( iSleep && SchedSleepStack() )
2440 iAttention = EFalse;
2442 DMMCStack::TMMCStackSchedStateEnum toDo = SchedSession();
2444 if( toDo == ESchedLoop )
2447 if( toDo == ESchedExit )
2450 if( SchedChooseJob() == ESchedExit )
2457 ((iStackState & KMMCStackStateWaitingDFC) ||
2458 (iCompReq | iInitialise | iAttention)==0) ||
2459 ((iSessionP) && (iSessionP->iState & KMMCSessStateAllowDirectCommands)))
2461 // Clear DFC flag here in case somebody was running scheduler in the background
2462 // when DFC turned up. This should never really happen, but with EPOC who knows
2463 iStackState &= ~KMMCStackStateRunning;
2464 iDFCRunning = EFalse;
2467 __KTRACE_OPT(KPBUS1,Kern::Printf("<mst:dos"));
2468 OstTraceFunctionExit1( DMMCSTACK_DOSCHEDULE_EXIT1, this );
2477 // DMMCStack:: --- Session service ---
2479 void DMMCStack::Add(DMMCSession* aSessP)
2481 * Adds session aSessP to the EntryQueue (asynchronous function)
2484 OstTraceFunctionEntryExt( DMMCSTACK_ADD_ENTRY, this );
2485 ASSERT_NOT_ISR_CONTEXT
2486 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Add %d",TUint(aSessP->iSessionID)));
2489 iEntryQueue.Add( aSessP );
2490 aSessP->iState |= KMMCSessStateEngaged;
2492 Scheduler( iAttention );
2493 OstTraceFunctionExit1( DMMCSTACK_ADD_EXIT, this );
2496 void DMMCStack::Abort(DMMCSession* aSessP)
2501 OstTraceFunctionEntryExt( DMMCSTACK_ABORT_ENTRY, this );
2502 ASSERT_NOT_ISR_CONTEXT
2503 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:abt"));
2505 if( !aSessP->IsEngaged() )
2507 OstTraceFunctionExit1( DMMCSTACK_ABORT_EXIT1, this );
2511 aSessP->iDoAbort = ETrue;
2512 aSessP->iMachine.Abort();
2514 Scheduler( iAbortReq );
2515 OstTraceFunctionExit1( DMMCSTACK_ABORT_EXIT2, this );
2518 void DMMCStack::Stop(DMMCSession* aSessP)
2520 * Signals session to stop
2523 OstTraceFunctionEntryExt( DMMCSTACK_STOP1_ENTRY, this );
2524 ASSERT_NOT_ISR_CONTEXT
2525 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:stp"));
2527 if( !aSessP->IsEngaged() )
2529 OstTraceFunctionExit1( DMMCSTACK_STOP1_EXIT1, this );
2533 aSessP->iDoStop = ETrue;
2534 OstTraceFunctionExit1( DMMCSTACK_STOP1_EXIT2, this );
2537 EXPORT_C void DMMCStack::Block(DMMCSession* aSessP, TUint32 aFlag)
2539 OstTraceFunctionEntryExt( DMMCSTACK_BLOCK_ENTRY, this );
2540 ASSERT_NOT_ISR_CONTEXT
2541 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:blk"));
2543 if( !aSessP->IsEngaged() )
2545 OstTraceFunctionExit1( DMMCSTACK_BLOCK_EXIT1, this );
2549 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:blk:[aFlag=%08x, iBlockOn=%08x]", aFlag, aSessP->iBlockOn));
2550 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_BLOCK, "aFlag=0x%08x; iBlockOn=0x%08x", aFlag, aSessP->iBlockOn );
2553 (void)__e32_atomic_ior_ord32(&aSessP->iBlockOn, aFlag);
2554 OstTraceFunctionExit1( DMMCSTACK_BLOCK_EXIT2, this );
2557 EXPORT_C void DMMCStack::UnBlock(DMMCSession* aSessP, TUint32 aFlag, TMMCErr anExitCode)
2559 * aFlag is a bitset of KMMCBlockOnXXX events that have occured. If the stack's
2560 * session is waiting on all of these events, then it is scheduled.
2563 OstTraceExt4(TRACE_FLOW, DMMCSTACK_UNBLOCK_ENTRY , "DMMCStack::UnBlock;aSessP=%x;aFlag=%x;anExitCode=%d;this=%x", (TUint) aSessP, (TUint) aFlag, (TInt) anExitCode, (TUint) this);
2564 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ubl"));
2568 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ubl:[aFlag=%08x, iBlockOn=%08x", aFlag, aSessP->iBlockOn));
2569 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_UNBLOCK, "aFlag=0x%08x; iBlockOn=0x%08x", aFlag, aSessP->iBlockOn );
2572 if( (aSessP->iBlockOn & aFlag) == 0 )
2574 OstTraceFunctionExit1( DMMCSTACK_UNBLOCK_EXIT1, this );
2578 // Must be either in a DFC or have the KMMCSessStateDoDFC flag set
2580 (aSessP->iState & KMMCSessStateDoDFC) != 0 ||
2581 NKern::CurrentContext() != NKern::EInterrupt,
2582 DMMCSocket::Panic(DMMCSocket::EMMCUnblockingInWrongContext));
2584 (void)__e32_atomic_and_ord32(&aSessP->iBlockOn, ~aFlag);
2585 aSessP->iMachine.SetExitCode( anExitCode );
2587 if( aSessP->iBlockOn == 0 )
2588 Scheduler( iAttention );
2590 OstTraceFunctionExit1( DMMCSTACK_UNBLOCK_EXIT2, this );
2593 void DMMCStack::UnlockStack(DMMCSession* aSessP)
2595 * Removes stack lock. Asynchronous function.
2598 OstTraceFunctionEntryExt( DMMCSTACK_UNLOCKSTACK_ENTRY, this );
2599 ASSERT_NOT_ISR_CONTEXT
2600 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ust"));
2602 aSessP->iBrokenLock = EFalse;
2604 if( aSessP == iLockingSessionP )
2606 iLockingSessionP = NULL;
2607 Scheduler( iAttention );
2609 OstTraceFunctionExit1( DMMCSTACK_UNLOCKSTACK_EXIT1, this );
2612 EXPORT_C TInt DMMCStack::Stop(TMMCard* aCardP)
2614 * Completes all sessions operating with a specified card with KMMCErrAbort.
2615 * Returns either KErrNone or KErrServerBusy.
2618 OstTraceFunctionEntryExt( DMMCSTACK_STOP2_ENTRY, this );
2619 ASSERT_NOT_ISR_CONTEXT
2620 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:stp"));
2624 if( iStackState & KMMCStackStateRunning )
2627 return KErrServerBusy; // can not operate in foreground
2630 iStackState |= KMMCStackStateRunning;
2638 while( (sessP = iWorkSet++) != NULL )
2639 if( sessP->iCardP == aCardP )
2640 MarkComplete( sessP, KMMCErrAbort );
2642 iReadyQueue.Point();
2644 while( (sessP = iReadyQueue) != NULL )
2645 if( sessP->iCardP == aCardP )
2647 MarkComplete( sessP, KMMCErrAbort );
2648 iReadyQueue.Remove();
2649 iWorkSet.Add( sessP );
2656 OstTraceFunctionExitExt( DMMCSTACK_STOP2_EXIT, this, KErrNone );
2660 void DMMCStack::MarkComplete(DMMCSession* aSessP, TMMCErr anExitCode)
2662 * Marks session to be completed on the next scheduler pass.
2665 OstTraceExt3(TRACE_FLOW, DMMCSTACK_MARKCOMPLETE_ENTRY ,"DMMCStack::MarkComplete;aSessP=%x;anExitCode=%d;this=%x", (TUint) aSessP, (TInt) anExitCode, (TUint) this);
2666 ASSERT_NOT_ISR_CONTEXT
2667 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:mcp"));
2669 aSessP->SynchBlock( KMMCBlockOnNoRun );
2670 aSessP->iMMCExitCode = anExitCode;
2671 aSessP->iDoComplete = ETrue;
2673 OstTraceFunctionExit1( DMMCSTACK_MARKCOMPLETE_EXIT, this );
2677 // DMMCStack:: --- Miscellaneous ---
2679 EXPORT_C TUint32 DMMCStack::EffectiveModes(const TMMCStackConfig& aClientConfig)
2681 * Calculates effective client modes as real client modes merged with iMasterConfig modes
2684 OstTraceFunctionEntry1( DMMCSTACK_EFFECTIVEMODES_ENTRY, this );
2685 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:em"));
2687 const TUint32 masterMode = (iMasterConfig.iModes & iMasterConfig.iUpdateMask) |
2688 (KMMCModeDefault & ~iMasterConfig.iUpdateMask);
2690 const TUint32 c = aClientConfig.iClientMask;
2691 const TUint32 u = aClientConfig.iUpdateMask;
2692 const TUint32 m = aClientConfig.iModes;
2693 const TUint32 userMode = (c & ((m & u) | ~u)) | (m & KMMCModeMask);
2694 const TUint32 userMask = (u | KMMCModeClientMask) &
2695 ((masterMode & KMMCModeMasterOverrides) | ~KMMCModeMasterOverrides);
2697 const TUint32 effectiveMode = (userMode & userMask) | (masterMode & ~userMask);
2699 if( effectiveMode & KMMCModeEnableClientConfig )
2701 OstTraceFunctionExitExt( DMMCSTACK_EFFECTIVEMODES_EXIT1, this, ( TUint )( effectiveMode ) );
2702 return effectiveMode;
2707 TUint32 ret = (effectiveMode & KMMCModeClientOverrides) |
2708 (masterMode & ~(KMMCModeClientOverrides | KMMCModeClientMask));
2709 OstTraceFunctionExitExt( DMMCSTACK_EFFECTIVEMODES_EXIT2, this, ( TUint )( ret ) );
2714 void DMMCStack::MergeConfig(DMMCSession* aSessP)
2716 * Merges client and master configuration into iConfig
2719 OstTraceFunctionEntryExt( DMMCSTACK_MERGECONFIG_ENTRY, this );
2720 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:mc"));
2722 TMMCStackConfig& cC = aSessP->iConfig;
2723 TMMCStackConfig& mC = iMasterConfig;
2724 const TUint32 modes = EffectiveModes( cC );
2725 const TUint32 mastM = mC.iClientMask;
2727 iConfig.iModes = modes;
2729 iConfig.iPollAttempts =
2730 (modes & KMMCModeClientPollAttempts)
2732 : ((mastM & KMMCModeClientPollAttempts) ? mC.iPollAttempts : KMMCMaxPollAttempts);
2734 iConfig.iTimeOutRetries =
2735 (modes & KMMCModeClientTimeOutRetries)
2736 ? cC.iTimeOutRetries
2737 : ((mastM & KMMCModeClientTimeOutRetries) ? mC.iTimeOutRetries : KMMCMaxTimeOutRetries);
2739 iConfig.iCRCRetries =
2740 (modes & KMMCModeClientCRCRetries)
2742 : ((mastM & KMMCModeClientCRCRetries) ? mC.iCRCRetries : KMMCMaxCRCRetries);
2744 iConfig.iUnlockRetries =
2745 (modes & KMMCModeClientUnlockRetries)
2747 : ((mastM & KMMCModeClientUnlockRetries) ? mC.iUnlockRetries : KMMCMaxUnlockRetries);
2749 iConfig.iOpCondBusyTimeout =
2750 (modes & KMMCModeClientiOpCondBusyTimeout)
2751 ? cC.iOpCondBusyTimeout
2752 : ((mastM & KMMCModeClientiOpCondBusyTimeout) ? mC.iOpCondBusyTimeout : KMMCMaxOpCondBusyTimeout);
2754 // There are no default constants defining BusConfig parameters.
2755 // iMasterConfig.iBusConfig must be initialised by ASSP layer
2757 // _?_? The code below can be modified later for a card controlled session
2758 // to include CSD analisys and calculate time-out and clock parameters on that basis.
2759 // As it written now, the defaults for all cards will be the same.
2761 if( modes & KMMCModeClientBusClock )
2763 TUint clock = cC.iBusConfig.iBusClock;
2764 if( clock > mC.iBusConfig.iBusClock )
2765 clock = mC.iBusConfig.iBusClock;
2766 if( clock < KMMCBusClockFOD )
2767 clock = KMMCBusClockFOD;
2770 else if( modes & KMMCModeCardControlled && aSessP->CardP() )
2772 TUint clock = MaxTranSpeedInKilohertz(*aSessP->CardP());
2773 if( clock > mC.iBusConfig.iBusClock )
2774 clock = mC.iBusConfig.iBusClock;
2775 if( clock < KMMCBusClockFOD )
2776 clock = KMMCBusClockFOD;
2780 DoSetClock(mC.iBusConfig.iBusClock);
2782 iConfig.iBusConfig.iClockIn = (modes & KMMCModeClientClockIn)
2783 ? cC.iBusConfig.iClockIn
2784 : mC.iBusConfig.iClockIn;
2786 iConfig.iBusConfig.iClockOut = (modes & KMMCModeClientClockOut)
2787 ? cC.iBusConfig.iClockOut
2788 : mC.iBusConfig.iClockOut;
2790 iConfig.iBusConfig.iResponseTimeOut = (modes & KMMCModeClientResponseTimeOut)
2791 ? cC.iBusConfig.iResponseTimeOut
2792 : mC.iBusConfig.iResponseTimeOut;
2794 iConfig.iBusConfig.iDataTimeOut = (modes & KMMCModeClientDataTimeOut)
2795 ? cC.iBusConfig.iDataTimeOut
2796 : mC.iBusConfig.iDataTimeOut;
2798 iConfig.iBusConfig.iBusyTimeOut = (modes & KMMCModeClientBusyTimeOut)
2799 ? cC.iBusConfig.iBusyTimeOut
2800 : mC.iBusConfig.iBusyTimeOut;
2801 OstTraceFunctionExit1( DMMCSTACK_MERGECONFIG_EXIT, this );
2804 TBool DMMCStack::StaticBlocks()
2806 * This function realises the potential blocking conditions of the current session.
2807 * Returns ETrue if the session has to be stopped right now
2810 OstTraceFunctionEntry1( DMMCSTACK_STATICBLOCKS_ENTRY, this );
2811 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:stb"));
2813 if( iSessionP->iDoStop )
2815 MarkComplete( iSessionP, KMMCErrAbort );
2816 OstTraceFunctionExitExt( DMMCSTACK_STATICBLOCKS_EXIT1, this, (TUint) ETrue );
2820 if( !iDFCRunning && (iSessionP->iState & KMMCSessStateDoDFC) )
2822 OstTraceFunctionExitExt( DMMCSTACK_STATICBLOCKS_EXIT2, this, (TUint) ETrue );
2826 TBool ret = (iSessionP->iState & KMMCSessStateDoReSchedule) != 0;
2827 OstTraceFunctionExitExt( DMMCSTACK_STATICBLOCKS_EXIT3, this, ret );
2832 EXPORT_C TBool DMMCStack::CardDetect(TUint /*aCardNumber*/)
2834 * Returns ETrue when a card is present in the card socket 'aCardNumber'.
2835 * Default implementation when not provided by ASSP layer.
2841 EXPORT_C TBool DMMCStack::WriteProtected(TUint /*aCardNumber*/)
2843 * Returns ETrue when the card in socket 'aCardNumber' is mechanically write
2845 * Default implementation when not provided by ASSP layer.
2851 // -------- DMMCStack State Machine functions --------
2854 // Auxiliary SM function service
2856 void DMMCStack::StackSessionCBST(TAny* aStackP)
2858 * Stack Session completion routine.
2861 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sscbs"));
2862 static_cast<DMMCStack *>(aStackP)->StackSessionCB();
2866 TInt DMMCStack::StackSessionCB()
2868 OstTraceFunctionEntry1( DMMCSTACK_STACKSESSIONCB_ENTRY, this );
2869 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sscb "));
2871 if (iStackState & KMMCStackStateSleepinProgress)
2873 // Sleep completed update stack state
2874 iStackState &= ~KMMCStackStateSleepinProgress;
2875 OstTraceFunctionExit1( DMMCSTACK_STACKSESSIONCB_EXIT1, this );
2879 TMMCErr mmcError = iStackSession->MMCExitCode();
2880 iStackState &= ~KMMCStackStateInitInProgress;
2882 TInt errCode = KErrNone;
2883 TBool anyLocked = EFalse;
2885 if (mmcError != KMMCErrNone)
2888 // StackSessionCB is the completion callback for the internal initialisation/power-up
2889 // session, so we never expect a callback while initialisation is still in progress.
2890 // - unless a card has failed to respond and the controller has not detected the error (!)
2892 errCode = KErrTimedOut; // this error code is not sticky, so should allow stack to be powered up again
2893 iInitialise = EFalse;
2894 iStackState &= ~(KMMCStackStateInitInProgress | KMMCStackStateInitPending | KMMCStackStateBusInconsistent);
2898 if (! iCardArray->CardsPresent())
2900 errCode = KErrNotReady;
2904 // Stack initialized ok, so complete request or start auto-unlock
2906 iInitState = EISDone;
2908 // remove bindings from password store for cards that do not have passwords
2910 for (i = 0; i < iMaxCardsInStack; ++i)
2912 TMMCard& cd = *(iCardArray->CardP(i));
2915 if (cd.HasPassword())
2919 TMapping* pmp = iSocket->iPasswordStore->FindMappingInStore(cd.CID());
2921 pmp->iState = TMapping::EStInvalid;
2923 } // if (cd.IsPresent())
2924 } // for (i = 0; i < iMaxCardsInStack; ++i)
2926 // if any cards are locked then launch auto-unlock mechanism
2930 // During power up (stack session context), we use the iAutoUnlockSession
2931 // to perform auto-unlock of the cards. Upon completion of the AutoUnlock
2932 // state machine, the local media subsystem is notified via ::PowerUpSequenceComplete
2934 iAutoUnlockSession.SetStack(this);
2935 iAutoUnlockSession.SetupCIMAutoUnlock();
2937 errCode = iAutoUnlockSession.Engage();
2938 if(errCode == KErrNone)
2940 // don't complete power up request yet
2941 // - This will be done in DMMCStack::AutoUnlockCB()
2942 OstTraceFunctionExit1( DMMCSTACK_STACKSESSIONCB_EXIT2, this );
2946 } // else ( !iCardArray->CardsPresent() )
2949 if(errCode == KErrNone)
2952 // No cards are locked (otherwise we will have engaged iAutoUnlockSession) and we
2953 // have encountered no error, so can now continue with the second-stage initialisation
2954 // phase (InitStackAfterUnlock). This performs initialisation that can only be
2955 // performed when a card is unlocked (such as setting bus width, speed class etc..)
2957 // iAutoUnlockSession::AutoUnlockCB will complete power-up by calling ::PowerUpSequenceComplete
2959 iAutoUnlockSession.SetStack(this);
2960 iAutoUnlockSession.iCardP = NULL;
2961 iAutoUnlockSession.SetupCIMInitStackAfterUnlock();
2962 errCode = iAutoUnlockSession.Engage();
2965 if(errCode != KErrNone)
2968 // We have encountered an error during power up initialisation
2969 // - Complete the request and notify the local media subsystem.
2972 // Calling PowerUpSequenceComplete() with an error may result in the media driver being closed which will delete
2973 // the media driver's session, so the stack must be made re-entrant here to allow all references to any engaged
2974 // sessions to be removed from the stack immediately to prevent the stack from referencing a deleted object
2975 __ASSERT_ALWAYS(iStackState & KMMCStackStateRunning, DMMCSocket::Panic(DMMCSocket::EMMCNotInDfcContext));
2976 iStackState &= ~KMMCStackStateRunning;
2977 iSocket->PowerUpSequenceComplete(errCode);
2978 iStackState |= KMMCStackStateRunning;
2982 OstTraceFunctionExit1( DMMCSTACK_STACKSESSIONCB_EXIT3, this );
2986 void DMMCStack::AutoUnlockCBST(TAny *aStackP)
2988 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:aucbs"));
2990 static_cast<DMMCStack *>(aStackP)->AutoUnlockCB();
2994 TInt DMMCStack::AutoUnlockCB()
2996 OstTraceFunctionEntry1( DMMCSTACK_AUTOUNLOCKCB_ENTRY, this );
2997 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:aucb"));
2999 // This is the session end callback for iAutoUnlockSession,
3000 // called at the end of the power up and initialisation process.
3002 TInt epocErr = iAutoUnlockSession.EpocErrorCode();
3004 // Calling PowerUpSequenceComplete() with an error may result in the media driver being closed which will delete
3005 // the media driver's session, so the stack must be made re-entrant here to allow all references to any engaged
3006 // sessions to be removed from the stack immediately to prevent the stack from referencing a deleted object
3007 __ASSERT_ALWAYS(iStackState & KMMCStackStateRunning, DMMCSocket::Panic(DMMCSocket::EMMCNotInDfcContext));
3008 if (epocErr != KErrNone)
3009 iStackState &= ~KMMCStackStateRunning;
3010 iSocket->PowerUpSequenceComplete(epocErr);
3011 iStackState |= KMMCStackStateRunning;
3013 OstTraceFunctionExit1( DMMCSTACK_AUTOUNLOCKCB_EXIT, this );
3018 inline TMMCErr DMMCStack::AttachCardSM()
3020 * This SM function must be invoked by every session which is CardControlled.
3022 * Some commands require that the data held by the stack for a given card is up to date.
3024 * These are card controlled commands. Before such commands are issued, this function should
3025 * first be invoked which performs the SEND_STATUS (CMD13) command.
3027 * @return MMC error code
3030 __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:ac"));
3039 DMMCSession& s=Session();
3040 OstTrace1( TRACE_INTERNALS, DMMCSTACK_ATTACHCARDSM1, "Current session=0x%x", &s );
3044 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ATTACHCARDSM2, "EStBegin" );
3045 if( s.iCardP == NULL )
3047 OstTraceFunctionExitExt( DMMCSTACK_ATTACHCARDSM_EXIT1, this, (TInt) KMMCErrNoCard );
3048 return KMMCErrNoCard;
3051 if( s.iCardP->iUsingSessionP != NULL && s.iCardP->iUsingSessionP != &s )
3053 s.SynchBlock( KMMCBlockOnCardInUse );
3057 if( s.iCardP->IsPresent() && s.iCardP->iCID == s.iCID )
3058 s.iCardP->iUsingSessionP = &s;
3061 OstTraceFunctionExitExt( DMMCSTACK_ATTACHCARDSM_EXIT2, this, (TInt) KMMCErrNoCard );
3062 return KMMCErrNoCard;
3065 s.iConfig.SetMode( KMMCModeCardControlled ); // for future context switching
3066 iConfig.SetMode( KMMCModeCardControlled ); // for this context
3068 // read card status if there are sticky bits in it
3069 if( (TUint32(s.iCardP->iStatus) & KMMCStatClearByReadMask) == 0 ||
3070 s.iCardP->iLastCommand == ECmdSendStatus ||
3071 s.iSessionID == ECIMNakedSession )
3074 s.PushCommandStack();
3075 s.FillCommandDesc( ECmdSendStatus, 0 );
3076 m.SetTraps( KMMCErrBasic ); // to restore command stack position to its original level
3077 SMF_INVOKES( ExecCommandSMST, EStAttStatus )
3079 SMF_STATE(EStAttStatus)
3081 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ATTACHCARDSM3, "EStAttStatus" );
3082 s.PopCommandStack();
3083 OstTraceFunctionExitExt( DMMCSTACK_ATTACHCARDSM_EXIT3, this, (TInt) err );
3089 inline TMMCErr DMMCStack::CIMInitStackSM()
3091 * Performs the Perform the CIM_INIT_STACK macro.
3092 * @return MMC error code
3102 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:InitStackSM"));
3104 DMMCSession& s=Session();
3105 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMINITSTACKSM1, "Current session=0x%x", &s );
3109 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMINITSTACKSM2, "EStBegin" );
3110 m.SetTraps( KMMCErrAll ); // to prevent this macro from infinite restarts via iInitialise
3112 SMF_INVOKES( CIMUpdateAcqSMST, EStInitDone )
3114 SMF_STATE(EStInitDone)
3116 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMINITSTACKSM3, "EStInitDone" );
3117 s.iState &= ~KMMCSessStateInProgress; // now we won't be restarted
3118 SchedGetOnDFC(); // StackSessionCB must be on DFC
3119 OstTraceFunctionExitExt( DMMCSTACK_CIMINITSTACKSM_EXIT, this, (TInt) err );
3120 SMF_RETURN( err ) // _?_ power cycles can be performed here if error
3125 TMMCErr DMMCStack::CIMUpdateAcqSM()
3127 * Performs an identification of a card stack. New cards are always
3128 * initialised but if KMMCStackStateInitInProgress is FALSE then existing
3129 * cards keep their configuration.
3130 * After successful execution of this function, all cards will be in standby
3132 * If iPoweredUp is FALSE then the stack is powered up and a full INIT_STACK
3133 * is performed (i.e all cards set to idle and then initialized).
3134 * @return MMC error code
3142 EStStartInterrogation,
3150 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:UpdAcqSM"));
3152 DMMCSession& s=Session();
3153 DMMCPsu* psu=(DMMCPsu*)iSocket->iVcc;
3154 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM1, "Current session=0x%x", &s );
3158 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM2, "EStBegin" );
3159 // This macro works naked and must not be preempted
3160 iConfig.RemoveMode( KMMCModeEnablePreemption | KMMCModeCardControlled );
3161 // Ensure DFC is running before and after powering up
3162 if( SchedGetOnDFC() ) // Such a direct synchronisation with Scheduler() can only
3163 SMF_WAIT // be used in this macro
3165 s.iState |= (KMMCSessStateInProgress | KMMCSessStateCritical);
3168 SMF_GOTOS( EStPoweredUp )
3170 // The bus is not powered so all cards need initialising - enforce INIT_STACK.
3171 iStackState |= KMMCStackStateInitInProgress;
3173 // Need to turn on the PSU at it's default voltage. Let the ASSP layer choose
3174 // this voltage by calling SetVoltage() with the full range the ASSP supports.
3175 iCurrentOpRange=(psu->VoltageSupported() & ~KMMCAdjustableOpVoltage);
3176 psu->SetVoltage(iCurrentOpRange);
3177 SMF_INVOKES( DoPowerUpSMST, EStPoweredUp )
3179 SMF_STATE(EStPoweredUp)
3181 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM3, "EStPoweredUp" );
3182 // Switch on the bus clock in identification mode
3183 SetBusConfigDefaults(iMasterConfig.iBusConfig, KMMCBusClockFOD);
3184 DoSetClock(KMMCBusClockFOD);
3186 // Make sure controller is in 1-bit bus width mode
3187 DoSetBusWidth(EBusWidth1);
3189 MergeConfig(&s); // This might take some time, but we are running in DFC here
3190 // Reinstate config bits after the merge
3191 iConfig.RemoveMode( KMMCModeEnablePreemption | KMMCModeCardControlled );
3192 SMF_INVOKES( InitClockOnSMST, EStClockOn ) // Feed init clock to the bus
3194 SMF_STATE(EStClockOn)
3196 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM4, "EStClockOn" );
3197 // Check if there are any cards present in the stack
3198 if (!HasCardsPresent())
3199 SMF_GOTOS( EStCheckStack )
3201 if( !InitStackInProgress() )
3202 SMF_GOTOS( EStStartInterrogation )
3204 // Increment the stack's initialiser pass number. Set the current session's pass
3205 // number to the new value. Pass number may be used later on to detect sessions
3206 // which have been re-initialized due to problems on the bus.
3207 if ((++iInitContext) == 0)
3208 iInitContext++; // Pass number must never be zero
3209 s.iInitContext = iInitContext; // this session is always in a proper context
3211 SMF_STATE(EStStartInterrogation)
3213 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM5, "EStStartInterrogation" );
3214 // NB: RCAs are not unlocked here. They will be unlocked one by one during the update of card info array.
3215 SMF_INVOKES( AcquireStackSMST, EStCheckStack )
3217 SMF_STATE(EStCheckStack)
3219 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM6, "EStCheckStack" );
3220 // Check that all known cards are still present by issuing select/deselect
3221 SMF_INVOKES( CheckStackSMST, EStCardCap )
3223 SMF_STATE(EStCardCap)
3225 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM7, "EStCardCap" );
3226 // Call a licencee-specific state machine to allow card capabilities to be modified.
3227 SMF_INVOKES( ModifyCardCapabilitySMST, EStIssueDSR )
3229 SMF_STATE(EStIssueDSR)
3231 // Now that we have updated the card entries, do any final initialisation
3232 // of the card entries and determine the maximum bus clock that can be employed.
3234 // If the bus is not multiplexed (ie - MMC stack), then the max clock is set to
3235 // the lowest common denominator of all cards in the stack. Otherwise (in the case
3236 // of a multiplexed bus such as SD), the highest clock is returned and the clock
3237 // rate is changed when a new card is selected.
3239 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM8, "EStIssueDSR" );
3241 iCardArray->UpdateAcquisitions(&maxClk);
3242 SetBusConfigDefaults( iMasterConfig.iBusConfig, maxClk );
3245 // merge clock from iMasterConfig.iBusConfig.iBusClock to
3246 // iConfig.iBusConfig.iBusClock - which the PSL should use to configure it's clock
3249 // switch to normal iConfig clock mode
3252 SMF_STATE(EStFinishUp)
3254 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMUPDATEACQSM9, "EStFinishUp" );
3255 s.iState &= ~(KMMCSessStateInProgress | KMMCSessStateCritical);
3257 // Update/Init stack has been completed.
3263 #define MHZ_TO_KHZ(valInMhz) ((valInMhz) * 1000)
3265 EXPORT_C TMMCErr DMMCStack::InitStackAfterUnlockSM()
3267 * Perform last-stage initialisation of the MMC card.
3268 * This implements initialiation that must occur only when the card
3269 * is unlocked (ie - immediately after unlocking, or during initialisation
3270 * if the card is already unlocked)
3279 EStGotModifiedExtendedCSD,
3280 EStEraseGroupDefSet,
3281 EStDetermineBusWidthAndClock,
3282 EStGotBusWidthAndClock,
3288 DMMCSession& s = Session();
3289 TBool initSingleCard = (s.CardP() == NULL) ? (TBool)EFalse : (TBool)ETrue;
3290 OstTrace1( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM1, "Current session=0x%x", &s );
3294 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM2, "EStBegin" );
3297 iSelectedCardIndex = iCxCardCount;
3298 TMMCard* cardP = iCardArray->CardP(iSelectedCardIndex);
3300 // if card not present or is locked, exit
3301 if ((!cardP->IsPresent()) || (cardP->IsLocked()))
3306 // If a card is currently indexed for initialisation, then only configure this one.
3307 // We assume that this has been called from the SD stack, so only one MMC card will be present on the bus
3309 SMF_GOTOS(EStGetExtendedCSD);
3312 // Initialising the entire MMC stack - start with the first card
3313 iSelectedCardIndex = -1;
3315 // ...fall through...
3317 SMF_STATE(EStTestNextCard)
3319 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM3, "EStTestNextCard" );
3322 if (++iSelectedCardIndex >= iCxCardCount)
3323 SMF_GOTOS(EStNoMoreCards);
3325 // if no card in this slot, try next one
3326 if (!iCardArray->CardP(iSelectedCardIndex)->IsPresent())
3327 SMF_GOTOS(EStTestNextCard);
3329 TMMCard* cardP = iCardArray->CardP(iSelectedCardIndex);
3332 // if card is locked, try the next one
3333 if(cardP->IsLocked())
3334 SMF_GOTOS(EStTestNextCard);
3336 SMF_STATE(EStGetExtendedCSD)
3338 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM4, "EStGetExtendedCSD" );
3340 // Get the Extended CSD if this is an MMC version 4 card
3342 __KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), SpecVers() %u", s.CardP()->CSD().SpecVers()));
3343 OstTrace1( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM5, "SpecVers()=%u", s.CardP()->CSD().SpecVers() );
3346 // clear the Extended CSD contents in case this is a pre-version 4 card or the read fails.
3347 memset(s.CardP()->iExtendedCSD.Ptr(), 0, KMMCExtendedCSDLength);
3349 if (s.CardP()->CSD().SpecVers() < 4)
3350 SMF_GOTOS(EStTestNextCard);
3352 m.SetTraps(KMMCErrResponseTimeOut | KMMCErrStatus | KMMCErrDataCRC | KMMCErrBypass); // KMMCErrDataCRC will pick up if the card is not in 1-bit mode
3354 s.FillCommandDesc(ECmdSendExtendedCSD);
3355 s.FillCommandArgs(0, KMMCExtendedCSDLength, iPSLBuf, KMMCExtendedCSDLength);
3357 __KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), Sending ECmdSendExtendedCSD"));
3358 SMF_INVOKES(CIMReadWriteBlocksSMST, EStGotExtendedCSD)
3360 SMF_STATE(EStGotExtendedCSD)
3362 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM6, "EStGotExtendedCSD" );
3363 if (err != KMMCErrNone)
3368 memcpy(s.CardP()->iExtendedCSD.Ptr(), iPSLBuf, KMMCExtendedCSDLength);
3370 // Call a licencee-specific state machine to allow the Extended CSD register to be modified.
3371 SMF_INVOKES( ModifyCardCapabilitySMST, EStGotModifiedExtendedCSD )
3373 SMF_STATE(EStGotModifiedExtendedCSD)
3375 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM7, "EStGotExtendedCSD" );
3377 __KTRACE_OPT(KPBUS1, Kern::Printf("Extended CSD"));
3378 __KTRACE_OPT(KPBUS1, Kern::Printf("CSDStructureVer: %u", s.CardP()->ExtendedCSD().CSDStructureVer()));
3379 __KTRACE_OPT(KPBUS1, Kern::Printf("ExtendedCSDRev: %u", s.CardP()->ExtendedCSD().ExtendedCSDRev()));
3380 __KTRACE_OPT(KPBUS1, Kern::Printf("-------------------------------"));
3381 __KTRACE_OPT(KPBUS1, Kern::Printf("SupportedCmdSet: %u", s.CardP()->ExtendedCSD().SupportedCmdSet()));
3382 __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass26Mhz360V: 0x%02X", s.CardP()->ExtendedCSD().PowerClass26Mhz360V()));
3383 __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass52Mhz360V: 0x%02X", s.CardP()->ExtendedCSD().PowerClass52Mhz360V()));
3384 __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass26Mhz195V: 0x%02X", s.CardP()->ExtendedCSD().PowerClass26Mhz195V()));
3385 __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass52Mhz195V: 0x%02X", s.CardP()->ExtendedCSD().PowerClass52Mhz195V()));
3386 __KTRACE_OPT(KPBUS1, Kern::Printf("CardType: %u", s.CardP()->ExtendedCSD().CardType()));
3387 __KTRACE_OPT(KPBUS1, Kern::Printf("CmdSet: %u", s.CardP()->ExtendedCSD().CmdSet()));
3388 __KTRACE_OPT(KPBUS1, Kern::Printf("CmdSetRev: %u", s.CardP()->ExtendedCSD().CmdSetRev()));
3389 __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass: %u", s.CardP()->ExtendedCSD().PowerClass()));
3390 __KTRACE_OPT(KPBUS1, Kern::Printf("HighSpeedTiming: %u", s.CardP()->ExtendedCSD().HighSpeedTiming()));
3391 __KTRACE_OPT(KPBUS1, Kern::Printf("HighCapacityEraseGroupSize: %u", s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize()));
3392 __KTRACE_OPT(KPBUS1, Kern::Printf("AccessSize: %u", s.CardP()->ExtendedCSD().AccessSize()));
3393 __KTRACE_OPT(KPBUS1, Kern::Printf("BootInfo: %u", s.CardP()->ExtendedCSD().BootInfo() ));
3394 __KTRACE_OPT(KPBUS1, Kern::Printf("BootSizeMultiple: %u", s.CardP()->ExtendedCSD().BootSizeMultiple() ));
3395 __KTRACE_OPT(KPBUS1, Kern::Printf("EraseTimeoutMultiple: %u", s.CardP()->ExtendedCSD().EraseTimeoutMultiple() ));
3396 __KTRACE_OPT(KPBUS1, Kern::Printf("ReliableWriteSector: %u", s.CardP()->ExtendedCSD().ReliableWriteSector() ));
3397 __KTRACE_OPT(KPBUS1, Kern::Printf("HighCapWriteProtGroupSize: %u", s.CardP()->ExtendedCSD().HighCapacityWriteProtectGroupSize() ));
3398 __KTRACE_OPT(KPBUS1, Kern::Printf("SleepCurrentVcc: %u", s.CardP()->ExtendedCSD().SleepCurrentVcc() ));
3399 __KTRACE_OPT(KPBUS1, Kern::Printf("SleepCurrentVccQ: %u", s.CardP()->ExtendedCSD().SleepCurrentVccQ()));
3400 __KTRACE_OPT(KPBUS1, Kern::Printf("SleepAwakeTimeout: %u", s.CardP()->ExtendedCSD().SleepAwakeTimeout()));
3401 __KTRACE_OPT(KPBUS1, Kern::Printf("BootConfig: %u", s.CardP()->ExtendedCSD().BootConfig()));
3402 __KTRACE_OPT(KPBUS1, Kern::Printf("BootBusWidth: %u", s.CardP()->ExtendedCSD().BootBusWidth()));
3403 __KTRACE_OPT(KPBUS1, Kern::Printf("EraseGroupDef: %u", s.CardP()->ExtendedCSD().EraseGroupDef()));
3405 OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM8, "CSDStructureVer=%u; ExtendedCSDRev=%u; SupportedCmdSet=%u", s.CardP()->ExtendedCSD().CSDStructureVer(), s.CardP()->ExtendedCSD().ExtendedCSDRev(), s.CardP()->ExtendedCSD().SupportedCmdSet() );
3406 OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM9, "PowerClass26Mhz360V=0x%02x; PowerClass52Mhz360V=0x%02x; PowerClass26Mhz195V=0x%02x; PowerClass52Mhz195V=0x%02x", s.CardP()->ExtendedCSD().PowerClass26Mhz360V(), s.CardP()->ExtendedCSD().PowerClass52Mhz360V(), s.CardP()->ExtendedCSD().PowerClass26Mhz195V(), s.CardP()->ExtendedCSD().PowerClass52Mhz195V() );
3407 OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM10, "CardType=%u; CmdSet=%u; CmdSetRev=%u; PowerClass=%u; HighSpeedTiming=%u", s.CardP()->ExtendedCSD().CardType(), s.CardP()->ExtendedCSD().CmdSet(), s.CardP()->ExtendedCSD().CmdSetRev(), s.CardP()->ExtendedCSD().PowerClass(), s.CardP()->ExtendedCSD().HighSpeedTiming() );
3408 OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM11, "HighCapacityEraseGroupSize=%u; AccessSize=%u; BootInfo=%u; BootSizeMultiple=%u; EraseTimeoutMultiple=%u", s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize(), s.CardP()->ExtendedCSD().AccessSize(), s.CardP()->ExtendedCSD().BootInfo(), s.CardP()->ExtendedCSD().BootSizeMultiple(), s.CardP()->ExtendedCSD().EraseTimeoutMultiple() );
3409 OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM12, "ReliableWriteSector=%u; HighCapWriteProtGroupSize=%u; SleepCurrentVcc=%u; SleepCurrentVccQ=%u; SleepAwakeTimeout=%u", s.CardP()->ExtendedCSD().ReliableWriteSector(), s.CardP()->ExtendedCSD().HighCapacityWriteProtectGroupSize(), s.CardP()->ExtendedCSD().SleepCurrentVcc(), s.CardP()->ExtendedCSD().SleepCurrentVccQ(), s.CardP()->ExtendedCSD().SleepAwakeTimeout() );
3410 OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM13, "BootConfig=%u; BootBusWidth=%u; EraseGroupDef=%u", s.CardP()->ExtendedCSD().BootConfig(), s.CardP()->ExtendedCSD().BootBusWidth(), s.CardP()->ExtendedCSD().EraseGroupDef() );
3412 if (s.CardP()->ExtendedCSD().ExtendedCSDRev() >= 3)
3414 if (!(s.CardP()->ExtendedCSD().EraseGroupDef()) && s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize())
3416 // Need to ensure that media is using correct erase group sizes.
3417 TMMCArgument arg = TExtendedCSD::GetWriteArg(
3418 TExtendedCSD::EWriteByte,
3419 TExtendedCSD::EEraseGroupDefIndex,
3420 TExtendedCSD::EEraseGrpDefEnableHighCapSizes,
3423 __KTRACE_OPT(KPBUS1, Kern::Printf(">Writing to EXT_CSD (EEraseGroupDefIndex), arg %08X", (TUint32) arg));
3424 OstTrace1( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM14, "Writing to EXT_CSD (EEraseGroupDefIndex); arg=0x%08x", (TUint32) arg );
3426 s.FillCommandDesc(ECmdSwitch, arg);
3428 SMF_INVOKES(ExecSwitchCommandST, EStEraseGroupDefSet)
3432 SMF_GOTOS(EStDetermineBusWidthAndClock)
3434 SMF_STATE(EStEraseGroupDefSet)
3436 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM15, "EStEraseGroupDefSet" );
3438 if (err == KMMCErrNone)
3440 // EEraseGroupDef has been updated succussfully,
3441 // update the Extended CSD to reflect this
3442 memset( s.CardP()->iExtendedCSD.Ptr()+TExtendedCSD::EEraseGroupDefIndex, TExtendedCSD::EEraseGrpDefEnableHighCapSizes, 1);
3445 SMF_STATE(EStDetermineBusWidthAndClock)
3447 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM16, "EStDetermineBusWidthAndClock" );
3448 SMF_INVOKES( DetermineBusWidthAndClockSMST, EStGotBusWidthAndClock )
3450 SMF_STATE(EStGotBusWidthAndClock)
3452 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM17, "EStGotBusWidthAndClock" );
3453 SMF_NEXTS(initSingleCard ? EStExit : EStTestNextCard)
3455 if(iMultiplexedBus || iCardArray->CardsPresent() == 1)
3457 SMF_CALL( ConfigureHighSpeedSMST )
3462 SMF_STATE(EStNoMoreCards)
3464 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM18, "EStNoMoreCards" );
3468 OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM19, "EStExit" );
3477 DetermineBusWidthAndClockSM()
3479 Reads the extended CSD register for all MMCV4 cards in the stack.
3480 If there is only one MMCV4 card, then an attempt is made to switch
3481 both the card and the controller to a higher clock rate (either 26MHz of 52MHz)
3482 and to a wider bus width (4 or 8 bits).
3483 The clock speed & bus width chosen depend on :
3485 - whether the card supports it
3486 - whether the controller supports it
3487 - whether the controller has the ability to supply enough current (the current used
3488 by the card can be read from the Extended CSD register)
3491 TMMCErr DMMCStack::DetermineBusWidthAndClockSM()
3502 DMMCSession& s = Session();
3503 TMMCard* cardP = iCardArray->CardP(iSelectedCardIndex);
3504 OstTrace1( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM1, "Current session=0x%x", &s );
3508 OstTrace0( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM2, "EStBegin" );
3509 // Trap Switch errors & no-response errors
3510 m.SetTraps(KMMCErrResponseTimeOut | KMMCErrStatus);
3512 __KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), iCxCardCount %u", iCxCardCount));
3515 SMF_STATE(EStWritePowerClass)
3517 OstTrace0( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM3, "EStWritePowerClass" );
3519 // Check the card type is valid
3520 // The only currently valid values for this field are 0x01 or 0x03
3521 TUint cardType = cardP->iExtendedCSD.CardType();
3522 if (cardType != (TExtendedCSD::EHighSpeedCard26Mhz) &&
3523 cardType != (TExtendedCSD::EHighSpeedCard26Mhz | TExtendedCSD::EHighSpeedCard52Mhz))
3525 __KTRACE_OPT(KPBUS1, Kern::Printf("Unsupported card type %u", cardType));
3526 OstTrace1( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM4, "Unsupported card type=%u", cardType );
3531 // determine the optimum bus width & clock speed which match the power constraints
3533 DetermineBusWidthAndClock(
3535 (iCurrentOpRange == KMMCOCRLowVoltage),
3539 // If the power class for the chosen width is different from the default,
3540 // send SWITCH cmd and write the POWER_CLASS byte of the EXT_CSD register
3543 TMMCArgument arg = TExtendedCSD::GetWriteArg(
3544 TExtendedCSD::EWriteByte,
3545 TExtendedCSD::EPowerClassIndex,
3549 __KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), Writing to EXT_CSD (EPowerClass), arg %08X", (TUint32) arg));
3550 OstTrace1( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM5, "Writing to EXT_CSD (EPowerClass); arg=0x%08x", (TUint32) arg );
3551 s.FillCommandDesc(ECmdSwitch, arg);
3552 SMF_INVOKES(ExecSwitchCommandST, EStStartBusTest)
3555 SMF_STATE(EStStartBusTest)
3557 OstTrace0( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM6, "EStStartBusTest" );
3559 if (err != KMMCErrNone)
3564 // We have determined the capabilities of the host and card.
3565 // - Before switching to the required bus width, perform the BUSTEST sequence
3566 SMF_INVOKES(ExecBusTestSMST, EStExit);
3570 OstTrace0( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCKSM7, "EStExit" );
3578 ConfigureHighSpeedSM()
3580 Reads the extended CSD register for all MMCV4 cards in the stack.
3581 If there is only one MMCV4 card, then an attempt is made to switch
3582 both the card and the controller to a higher clock rate (either 26MHz of 52MHz)
3583 and to a wider bus width (4 or 8 bits).
3584 The clock speed & bus width chosen depend on :
3586 - whether the card supports it
3587 - whether the controller supports it
3588 - whether the controller has the ability to supply enough current (the current used
3589 by the card can be read from the Extended CSD register)
3592 TMMCErr DMMCStack::ConfigureHighSpeedSM()
3597 EStConfigureBusWidth,
3604 DMMCSession& s = Session();
3605 TMMCard* cardP = iCardArray->CardP(iSelectedCardIndex);
3606 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM1, "Current session=0x%x", &s );
3610 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM2, "EStBegin" );
3612 // Trap Switch errors & no-response errors
3613 m.SetTraps(KMMCErrResponseTimeOut | KMMCErrStatus);
3615 __KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), iCxCardCount %u", iCxCardCount));
3616 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM3, "iCxCardCount=%d", iCxCardCount );
3618 cardP->SetHighSpeedClock(0);
3620 // Check the card type is valid
3621 // The only currently valid values for this field are 0x01 or 0x03
3622 TUint cardType = cardP->iExtendedCSD.CardType();
3623 if (cardType != (TExtendedCSD::EHighSpeedCard26Mhz) &&
3624 cardType != (TExtendedCSD::EHighSpeedCard26Mhz | TExtendedCSD::EHighSpeedCard52Mhz))
3626 __KTRACE_OPT(KPBUS1, Kern::Printf("Unsupported card type %u", cardType));
3627 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM4, "Unsupported card type=%u", cardType );
3631 // If the bus width is 4 or 8, send SWITCH cmd and write the BUS_WIDTH byte of the EXT_CSD register
3633 if (iBusWidthAndClock != E1Bit20Mhz)
3635 TMMCArgument arg = TExtendedCSD::GetWriteArg(
3636 TExtendedCSD::EWriteByte,
3637 TExtendedCSD::EBusWidthModeIndex,
3638 (iBusWidthAndClock & E4BitMask) ? TExtendedCSD::EExtCsdBusWidth4 : TExtendedCSD::EExtCsdBusWidth8,
3641 __KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), Writing to EXT_CSD (EBusWidthMode), arg %08X", (TUint32) arg));
3642 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM5, "Writing to EXT_CSD (EBusWidthMode); arg=0x%x", (TUint32) arg );
3643 s.FillCommandDesc(ECmdSwitch, arg);
3644 SMF_INVOKES(ExecSwitchCommandST, EStConfigureBusWidth)
3647 SMF_STATE(EStConfigureBusWidth)
3649 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM6, "EStConfigureBusWidth" );
3651 if (err != KMMCErrNone)
3656 // Ensure that the controller is configured for an 4 or 8 bit bus
3657 // - BUSTEST should have already done this
3658 if (iBusWidthAndClock & E4BitMask)
3660 DoSetBusWidth(EBusWidth4);
3662 else if (iBusWidthAndClock & E8BitMask)
3664 DoSetBusWidth(EBusWidth8);
3666 // fall through to next state
3668 SMF_STATE(EStWriteHsTiming)
3670 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM7, "EStWriteHsTiming" );
3672 if (iBusWidthAndClock == E1Bit20Mhz)
3675 TMMCArgument arg = TExtendedCSD::GetWriteArg(
3676 TExtendedCSD::EWriteByte,
3677 TExtendedCSD::EHighSpeedInterfaceTimingIndex,
3678 1, // turn on high speed (26 or 52 Mhz, depending on the card type)
3681 __KTRACE_OPT(KPBUS1, Kern::Printf(">ConfigureHighSpeed(), Writing to EXT_CSD (EHighSpeedInterfaceTiming), arg %08X", (TUint32) arg));
3682 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM8, "Writing to EXT_CSD (EHighSpeedInterfaceTiming); arg=0x%x", (TUint32) arg );
3683 s.FillCommandDesc(ECmdSwitch, arg);
3684 SMF_INVOKES(ExecSwitchCommandST, EStConfigureClock)
3687 SMF_STATE(EStConfigureClock)
3689 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM9, "EStConfigureClock" );
3691 if (err != KMMCErrNone)
3693 DoSetBusWidth(EBusWidth1);
3697 cardP->SetHighSpeedClock(
3698 MHZ_TO_KHZ(((iBusWidthAndClock & E52MhzMask) ?
3699 TMMCMachineInfoV4::EClockSpeed52Mhz:
3700 TMMCMachineInfoV4::EClockSpeed26Mhz)));
3704 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CONFIGUREHIGHSPEEDSM10, "EStExit" );
3711 // Issue a switch command and then wait while he card is in prg state
3713 TMMCErr DMMCStack::ExecSwitchCommand()
3723 DMMCSession& s=Session();
3724 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSWITCHCOMMAND1, "Current session=0x%x", &s );
3727 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSWITCHCOMMAND2, "EStBegin" );
3728 SMF_INVOKES(ExecCommandSMST, EStSendStatus)
3730 SMF_STATE(EStSendStatus)
3731 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSWITCHCOMMAND3, "EStSendStatus" );
3732 s.FillCommandDesc(ECmdSendStatus, 0);
3733 SMF_INVOKES(ExecCommandSMST, EStGetStatus)
3735 SMF_STATE(EStGetStatus)
3736 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSWITCHCOMMAND4, "EStGetStatus" );
3737 const TMMCStatus st(s.ResponseP());
3739 const TMMCardStateEnum st1 = st.State();
3740 if (st1 == ECardStatePrg)
3742 SMF_INVOKES(ProgramTimerSMST, EStSendStatus);
3745 // Fall through if CURRENT_STATE is not PGM
3750 // Issue CMD5 to change device status to Sleep mode
3752 TMMCErr DMMCStack::ExecSleepCommandSM()
3759 EStSleepAwakeIssued,
3760 EStUpdateStackState,
3765 DMMCSession& s=Session();
3766 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM1, "Current session=0x%x", &s );
3770 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM2, "EStBegin" );
3772 __KTRACE_OPT(KPBUS1, Kern::Printf(">ExecSleepCommandSM()"));
3774 iAutoUnlockIndex = -1;
3777 SMF_STATE(EStIndexNxtCard)
3779 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM3, "EStIndexNxtCard" );
3780 __KTRACE_OPT(KPBUS1, Kern::Printf(">EStIndexNxtCard"));
3781 // the cycle is finished when iAutoUnlockIndex == KMaxMultiMediaCardsPerStack
3782 if(iAutoUnlockIndex >= TInt(KMaxMMCardsPerStack))
3784 SMF_GOTOS(EStUpdateStackState);
3787 // Potentionaly more than one eMMC device attached to Controller
3788 // need to select each device and determine if Sleep can be issued
3789 TBool useIndex = EFalse;
3790 for (++iAutoUnlockIndex; iAutoUnlockIndex < TInt(KMaxMMCardsPerStack); ++iAutoUnlockIndex)
3792 // card must be present and a valid 4.3 device
3793 TMMCard* cardP = iCardArray->CardP(iAutoUnlockIndex);
3794 useIndex = ( (cardP->IsPresent()) &&
3795 (cardP->ExtendedCSD().ExtendedCSDRev() >= 3) &&
3796 (cardP->iStatus != ECardStateSlp) );
3798 // don't increment iAutoUnlockIndex in continuation loop
3801 __KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: is v4.3 device",iAutoUnlockIndex));
3802 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM4, "Card[%d]: is v4.3+ device", iAutoUnlockIndex );
3809 SMF_GOTOS(EStUpdateStackState);
3812 TMMCard &cd = *(iCardArray->CardP(iAutoUnlockIndex));
3815 s.PushCommandStack();
3816 s.FillCommandDesc(ECmdSleepAwake, KBit15);
3818 // CMD5 is an AC command, ExecCommandSMST will automatically issue a deselect
3819 SMF_INVOKES(ExecCommandSMST, EStSleepAwakeIssued)
3821 SMF_STATE(EStSleepAwakeIssued)
3823 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM5, "EStSleepAwakeIssued" );
3824 __KTRACE_OPT(KPBUS1, Kern::Printf(">EStSleepAwakeIssued!"));
3826 const TMMCStatus status(s.ResponseP());
3828 s.PopCommandStack();
3830 if(status.State() == ECardStateStby || status.State() == ECardStateSlp)
3832 // R1b is issued before Sleep state is achieved and
3833 // will therefore return the previous state which was Standby
3834 __KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: SLEEP",iAutoUnlockIndex));
3835 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM6, "Card[%d]: SLEEP", iAutoUnlockIndex );
3837 // Ensure card status is ECardStateSlp
3838 s.CardP()->iStatus.UpdateState(ECardStateSlp);
3840 // Update Stack state to indicate media is sleep mode
3841 iStackState |= KMMCStackStateSleep;
3845 __KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: UNKNOWN",iAutoUnlockIndex));
3846 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM7, "Card[%d]: UNKNOWN", iAutoUnlockIndex );
3848 return (KMMCErrStatus);
3851 SMF_GOTOS(EStIndexNxtCard)
3853 SMF_STATE(EStUpdateStackState)
3855 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM8, "EStUpdateStackState" );
3856 if (iStackState & KMMCStackStateSleep)
3858 // Media has been transitioned to sleep state
3859 iStackState &= ~KMMCStackStateSleep;
3861 // VccCore may now be switched off
3862 iSocket->iVccCore->SetState(EPsuOff);
3865 // No media transitioned to sleep state or media was already in sleep state,
3870 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECSLEEPCOMMANDSM9, "EStDone" );
3871 __KTRACE_OPT(KPBUS1, Kern::Printf("<ExecSleepCommandSM()"));
3877 //Issue CMD5 to change devices into STANDBY state
3878 TMMCErr DMMCStack::ExecAwakeCommandSM()
3889 DMMCSession& s=Session();
3890 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM1, "Current session=0x%x", &s );
3894 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM2, "EStBegin" );
3895 __KTRACE_OPT(KPBUS1, Kern::Printf(">ExecAwakeCommandSM()"));
3897 // Call PSL to ensure VccQ is powered up before continuing
3898 SMF_INVOKES( DoWakeUpSMST, EStPoweredUp )
3900 SMF_STATE(EStPoweredUp)
3902 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM3, "EStPoweredUp" );
3903 __KTRACE_OPT(KPBUS1, Kern::Printf("VccQ Powered Up"));
3905 //Issue CMD5 to awaken media
3906 s.PushCommandStack();
3907 s.FillCommandDesc(ECmdSleepAwake);
3908 s.Command().iArgument.SetRCA(s.CardP()->RCA());
3910 SMF_INVOKES(IssueCommandCheckResponseSMST, EStAwakeIssued)
3912 SMF_STATE(EStAwakeIssued)
3914 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM4, "EStAwakeIssued" );
3915 __KTRACE_OPT(KPBUS1, Kern::Printf(">>EStAwakeIssued!"));
3917 TMMCStatus status(s.ResponseP());
3919 if(status.State() == ECardStateStby || status.State() == ECardStateSlp)
3921 // R1b is issued before Standby state is achieved and
3922 // will therefore return the previous state which was Sleep
3923 __KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: STANDBY",iAutoUnlockIndex));
3924 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM5, "Card[%d]: STANDBY", iAutoUnlockIndex );
3925 s.CardP()->iStatus.UpdateState(ECardStateStby);
3929 __KTRACE_OPT(KPBUS1, Kern::Printf(">Card[%d]: UNKNOWN",iAutoUnlockIndex));
3930 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM6, "Card[%d]: UNKNOWN", iAutoUnlockIndex );
3931 OstTraceFunctionExitExt( DMMCSTACK_EXECAWAKECOMMANDSM_EXIT, this, (TInt) KMMCErrStatus );
3932 return KMMCErrStatus;
3935 s.PopCommandStack();
3939 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECAWAKECOMMANDSM7, "EStDone" );
3940 __KTRACE_OPT(KPBUS1, Kern::Printf("<ExecAwakeCommandSM()"));
3946 // determine the maximum bus width and clock speed supported by both the controller
3947 // and the card which fits the power constraints.
3948 void DMMCStack::DetermineBusWidthAndClock(
3949 const TMMCard& aCard,
3952 TBusWidthAndClock& aBusWidthAndClock)
3954 OstTraceExt2(TRACE_FLOW, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCK_ENTRY, "DMMCStack::DetermineBusWidthAndClock;aLowVoltage=%d;this=%x", (TInt) aLowVoltage, (TUint) this);
3956 // Set default return values - in case power constraints aren't matched
3958 aBusWidthAndClock = E1Bit20Mhz;
3960 // Get the bus widths & clocks supported by the controller
3961 // NB If the PSL doesn not support TMMCMachineInfoV4, return
3962 TMMCMachineInfoV4 machineInfo;
3963 TMMCMachineInfoV4Pckg machineInfoPckg(machineInfo);
3964 MachineInfo(machineInfoPckg);
3965 if (machineInfo.iVersion < TMMCMachineInfoV4::EVersion4)
3967 OstTraceFunctionExit1( DMMCSTACK_DETERMINEBUSWIDTHANDCLOCK_EXIT1, this );
3971 TBusWidth maxBusWidth = machineInfo.iMaxBusWidth;
3972 TInt maxClockSpeedInMhz = machineInfo.iMaxClockSpeedInMhz;
3974 TUint32 controllerWidthAndClock = E1Bit20Mhz;
3976 if (maxClockSpeedInMhz >= TMMCMachineInfoV4::EClockSpeed26Mhz && maxBusWidth >= EBusWidth4)
3977 controllerWidthAndClock|= E4Bits26Mhz;
3978 if (maxClockSpeedInMhz >= TMMCMachineInfoV4::EClockSpeed52Mhz && maxBusWidth >= EBusWidth4)
3979 controllerWidthAndClock|= E4Bits52Mhz;
3981 if (maxClockSpeedInMhz >= TMMCMachineInfoV4::EClockSpeed26Mhz && maxBusWidth >= EBusWidth8)
3982 controllerWidthAndClock|= E8Bits26Mhz;
3983 if (maxClockSpeedInMhz >= TMMCMachineInfoV4::EClockSpeed52Mhz && maxBusWidth >= EBusWidth8)
3984 controllerWidthAndClock|= E8Bits52Mhz;
3986 // Get the bus widths & clocks supported by the card
3987 TUint32 cardWidthAndClock = E1Bit20Mhz;
3989 if (aCard.ExtendedCSD().CardType() & TExtendedCSD::EHighSpeedCard26Mhz)
3990 cardWidthAndClock|= E4Bits26Mhz | E8Bits26Mhz;
3991 if (aCard.ExtendedCSD().CardType() & TExtendedCSD::EHighSpeedCard52Mhz)
3992 cardWidthAndClock|= E4Bits52Mhz | E8Bits52Mhz;
3995 // Get the bus widths & clocks supported by both the controller & card
3996 // by AND-ing them together,
3997 TUint32 supportedWidthAndClock = controllerWidthAndClock & cardWidthAndClock;
3999 // Iterate through all the modes (starting at the fastest) until we find one
4000 // that is supported by both card & controller and fits the power constraints
4001 TUint powerClass = 0;
4002 for (TUint targetWidthAndClock = E8Bits52Mhz; targetWidthAndClock != 0; targetWidthAndClock>>= 1)
4004 if ((supportedWidthAndClock & targetWidthAndClock) == 0)
4007 powerClass = GetPowerClass(aCard, TBusWidthAndClock(targetWidthAndClock), aLowVoltage);
4009 // can the controller support this power class ?
4010 if (powerClass > (aLowVoltage ? machineInfo.iLowVoltagePowerClass : machineInfo.iHighVoltagePowerClass ))
4013 aPowerClass = powerClass;
4014 aBusWidthAndClock = TBusWidthAndClock(targetWidthAndClock);
4018 __KTRACE_OPT(KPBUS1, Kern::Printf("aPowerClass %u, targetWidthAndClock = %08X", aPowerClass, aBusWidthAndClock));
4019 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_DETERMINEBUSWIDTHANDCLOCK, "aPowerClass=%u; targetWidthAndClock=0x%08x", aPowerClass, (TUint) aBusWidthAndClock );
4020 OstTraceFunctionExit1( DMMCSTACK_DETERMINEBUSWIDTHANDCLOCK_EXIT2, this );
4023 TUint DMMCStack::GetPowerClass(const TMMCard& aCard, TBusWidthAndClock aWidthAndClock, TBool aLowVoltage)
4025 OstTraceExt3(TRACE_FLOW, DMMCSTACK_GETPOWERCLASS_ENTRY, "DMMCStack::GetPowerClass;aWidthAndClock=%d;aLowVoltage=%d;this=%x", (TInt) aWidthAndClock, (TInt) aLowVoltage, (TUint) this);
4026 // The power class for 4 bit bus configurations is in the low nibble,
4027 // The power class for 8 bit bus configurations is in the high nibble,
4028 #define LO_NIBBLE(val) (val & 0x0F)
4029 #define HI_NIBBLE(val) ((val >> 4) & 0x0F)
4031 const TExtendedCSD& extendedCSD = aCard.ExtendedCSD();
4033 TUint powerClass = 0;
4037 switch( aWidthAndClock)
4040 powerClass = LO_NIBBLE(extendedCSD.PowerClass26Mhz195V());
4043 powerClass = LO_NIBBLE(extendedCSD.PowerClass52Mhz195V());
4046 powerClass = HI_NIBBLE(extendedCSD.PowerClass26Mhz195V());
4049 powerClass = HI_NIBBLE(extendedCSD.PowerClass52Mhz195V());
4058 switch( aWidthAndClock)
4061 powerClass = LO_NIBBLE(extendedCSD.PowerClass26Mhz360V());
4064 powerClass = LO_NIBBLE(extendedCSD.PowerClass52Mhz360V());
4067 powerClass = HI_NIBBLE(extendedCSD.PowerClass26Mhz360V());
4070 powerClass = HI_NIBBLE(extendedCSD.PowerClass52Mhz360V());
4078 OstTraceFunctionExitExt( DMMCSTACK_GETPOWERCLASS_EXIT, this, powerClass );
4083 // Execute the BUSTEST procedure for a given bus width
4085 TMMCErr DMMCStack::ExecBusTestSM()
4097 DMMCSession& s = Session();
4098 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM1, "Current session=0x%x", &s );
4102 // Start the BUSTEST sequence at the maximum supported by the PSL
4103 // - iSpare[0] keeps track of the current bus width
4105 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM2, "EStBegin" );
4106 if (iBusWidthAndClock & E8BitMask)
4108 iSpare[0] = EBusWidth8;
4109 __KTRACE_OPT(KPBUS1, Kern::Printf("...Hardware supports 8-bit bus"));
4110 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM3, "Hardware supports 8-bit bus" );
4112 else if(iBusWidthAndClock & E4BitMask)
4114 iSpare[0] = EBusWidth4;
4115 __KTRACE_OPT(KPBUS1, Kern::Printf("...Hardware supports 4-bit bus"));
4116 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM4, "Hardware supports 4-bit bus" );
4120 __KTRACE_OPT(KPBUS1, Kern::Printf("...Hardware supports 1-bit bus"));
4121 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM5, "Hardware supports 1-bit bus" );
4122 iSpare[0] = EBusWidth1;
4125 // remove KMMCModeCardControlled so that IssueCommandCheckResponseSMST doesn't try to
4126 // override the bus width & clock rate using the card settings
4127 iConfig.RemoveMode( KMMCModeCardControlled );
4129 SMF_STATE(EstSendBusTest_W)
4131 // Issue the BUSTEST_W command
4133 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM6, "EStSendBusTest_W" );
4138 // Set the host to 8-bit mode
4139 __KTRACE_OPT(KPBUS1, Kern::Printf("BUSTEST : EBusWidth8"));
4140 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM7, "BUSTEST : EBusWidth8" );
4141 DoSetBusWidth(EBusWidth8);
4147 // Set the host to 4-bit mode
4148 __KTRACE_OPT(KPBUS1, Kern::Printf("BUSTEST : EBusWidth4"));
4149 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM8, "BUSTEST : EBusWidth4" );
4150 DoSetBusWidth(EBusWidth4);
4157 // Set the host to 1-bit mode
4158 __KTRACE_OPT(KPBUS1, Kern::Printf("BUSTEST : EBusWidth1"));
4159 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM9, "BUSTEST : EBusWidth1" );
4160 DoSetBusWidth(EBusWidth1);
4168 __KTRACE_OPT(KPBUS1, Kern::Printf("...Issue BUSTEST_W [%02x:%02x]", iPSLBuf[1], iPSLBuf[0]));
4169 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM10, "Issue BUSTEST_W [%02x:%02x]", (TUint) iPSLBuf[1], (TUint) iPSLBuf[0] );
4171 m.SetTraps(KMMCErrDataCRC); // CRC check is optional for BUSTEST
4173 s.FillCommandDesc(ECmdBustest_W);
4174 s.FillCommandArgs(0, length, &iPSLBuf[0], length);
4175 SMF_INVOKES(IssueCommandCheckResponseSMST, EstSendBusTest_R)
4177 SMF_STATE(EstSendBusTest_R)
4179 // Issue the BUSTEST_R command
4181 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM11, "EStSendBusTest_R" );
4182 __KTRACE_OPT(KPBUS1, Kern::Printf("...got BUSTEST_W response : %02x", err));
4183 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM12, "Got BUSTEST_W response=0x%02x", err );
4185 if(err == KMMCErrNone || err == KMMCErrDataCRC)
4187 __KTRACE_OPT(KPBUS1, Kern::Printf("...sending BUSTEST_R"));
4188 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM13, "Sending BUSTEST_R" );
4193 s.FillCommandDesc(ECmdBustest_R);
4194 s.FillCommandArgs(0, 2, &iPSLBuf[0], 2);
4195 SMF_INVOKES(IssueCommandCheckResponseSMST, EstGotBusTest_R)
4199 OstTraceFunctionExitExt( DMMCSTACK_EXECBUSTESTSM_EXIT, this, (TInt) KMMCErrNotSupported );
4200 SMF_RETURN(KMMCErrNotSupported);
4203 SMF_STATE(EstGotBusTest_R)
4205 // Validate the BUSTEST_R data with that issued by BUSTEST_W
4207 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM14, "EStGotBusTest_R" );
4208 __KTRACE_OPT(KPBUS1, Kern::Printf("...got BUSTEST_R response [%02x:%02x] : err(%02x)", iPSLBuf[1], iPSLBuf[0], err));
4209 OstTraceExt3( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM15, "Got BUSTEST_R response [%02x:%02x]; err(%x)", (TUint) iPSLBuf[1], (TUint) iPSLBuf[0], (TUint) err );
4211 TBool retry = EFalse;
4212 TBool is52MHzSupported = (iBusWidthAndClock & E52MhzMask) ? (TBool)ETrue : (TBool)EFalse;
4218 if(iPSLBuf[0] == 0xAA && iPSLBuf[1] == 0x55)
4220 // 8-Bit bus supported
4221 iBusWidthAndClock = is52MHzSupported ? E8Bits52Mhz : E8Bits26Mhz;
4225 // 8-Bit bus not supported - retry with 4-Bit
4227 iSpare[0] = EBusWidth4;
4234 if(iPSLBuf[0] == 0xA5)
4236 // 4-Bit Bus Supported
4237 iBusWidthAndClock = is52MHzSupported ? E4Bits52Mhz : E4Bits26Mhz;
4241 // 4-Bit bus not supported - retry with 1-Bit
4243 iSpare[0] = EBusWidth1;
4250 if((iPSLBuf[0] & 0xC0) == 0x80)
4252 // 1-Bit Bus Supported
4253 iBusWidthAndClock = E1Bit20Mhz;
4256 // Failed to perform BUSTEST with 1-Bit bus.
4257 // - We can't recover from this, but let's continue using low-speed 1-Bit mode
4258 iBusWidthAndClock = E1Bit20Mhz;
4263 DMMCSocket::Panic(DMMCSocket::EMMCBadBusWidth);
4269 __KTRACE_OPT(KPBUS1, Kern::Printf("...BUSTEST Failed : Retry"));
4270 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM16, "BUSTEST Failed : Retry" );
4271 SMF_GOTOS(EstSendBusTest_W);
4274 switch(iBusWidthAndClock)
4277 iCardArray->CardP(iSelectedCardIndex)->SetBusWidth(1);
4282 iCardArray->CardP(iSelectedCardIndex)->SetBusWidth(4);
4287 iCardArray->CardP(iSelectedCardIndex)->SetBusWidth(8);
4291 __KTRACE_OPT(KPBUS1, Kern::Printf("...BUSTEST OK"));
4292 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM17, "BUSTEST OK" );
4294 DoSetBusWidth(EBusWidth1);
4297 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECBUSTESTSM18, "EStExit" );
4298 iConfig.SetMode( KMMCModeCardControlled );
4305 * PSL-supplied method to retrieve an interface.
4306 * The caller should set aInterfacePtr to NULL before calling
4307 * the PSL should only modify aInterfacePtr if it supports the interface
4308 * The default implementation here does nothing
4311 EXPORT_C void DMMCStack::GetInterface(TInterfaceId aInterfaceId, MInterface*& aInterfacePtr)
4313 OstTraceFunctionEntry1( DMMCSTACK_GETINTERFACE_ENTRY, this );
4314 if (aInterfaceId == KInterfaceCancelSession)
4316 DMMCSession* session = (DMMCSession*&) aInterfacePtr;
4318 UnlockStack(session);
4321 OstTraceFunctionExit1( DMMCSTACK_GETINTERFACE_EXIT, this );
4325 TMMCErr DMMCStack::GoIdleSM()
4327 * Issues GO_IDLE_STATE twice with a RetryGap between them.
4328 * After that the bus context ought to be considered as "known".
4329 * @return MMC error code
4340 DMMCSession& s=Session();
4341 OstTrace1( TRACE_INTERNALS, DMMCSTACK_GOIDLESM1, "Current session=0x%x", &s );
4345 OstTrace0( TRACE_INTERNALS, DMMCSTACK_GOIDLESM2, "EStBegin" );
4346 s.FillCommandDesc( ECmdGoIdleState, 0 );
4347 iCxPollRetryCount = KMMCIdleCommandsAtRestart;
4349 SMF_STATE(EStIdleLoop)
4350 OstTrace0( TRACE_INTERNALS, DMMCSTACK_GOIDLESM3, "EStIdleLoop" );
4351 SMF_INVOKES( ExecCommandSMST, EStIdleEndCheck )
4353 SMF_STATE(EStIdleEndCheck)
4355 OstTrace0( TRACE_INTERNALS, DMMCSTACK_GOIDLESM4, "EStIdleEndCheck" );
4356 if( --iCxPollRetryCount > 0 )
4357 SMF_INVOKES( RetryGapTimerSMST, EStIdleLoop )
4359 iStackState &= ~(KMMCStackStateDoDeselect|KMMCStackStateBusInconsistent);
4362 // According to the spec, the default bus width after power up or GO_IDLE is 1 bit bus width
4363 DoSetBusWidth(EBusWidth1);
4368 EXPORT_C TMMCErr DMMCStack::AcquireStackSM()
4370 * This macro acquires new cards in an MMC - bus topology stack.
4371 * It starts with the Controller reading the operating conditions of the
4372 * cards in the stack (SEND_OP_COND - CMD1). Then, any new cards in the stack
4373 * are identified (ALL_SEND_CID - CMD2) and each one is assigned a relative
4374 * card address (SET_RCA - CMD3). This is done by systematically broadcasting
4375 * CMD2 to all cards on the bus until all uninitialized cards have responded.
4376 * Finally the card specific data (SEND_CSD - CMD9) is read from each card.
4377 * @return MMC error code
4386 EStSetRangeBusyCheck,
4397 DMMCSession& s=Session();
4398 DMMCPsu* psu=(DMMCPsu*)iSocket->iVcc;
4399 OstTrace1( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM1, "Current session=0x%x", &s );
4403 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM2, "EStBegin" );
4404 iRCAPool.ReleaseUnlocked();
4405 iCxPollRetryCount = 0; // Reset max number of poll attempts on card busy
4407 SMF_INVOKES( GoIdleSMST, EStIdle )
4411 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM3, "EStIdle" );
4412 // If this platform doesn't support an adjustable voltage PSU then there is
4413 // no point in interogating the card(s) present for their supported range
4414 if ( !(psu->VoltageSupported()&KMMCAdjustableOpVoltage) )
4416 // if the PSU isn't adjustable then it can't support low voltage mode
4417 iCurrentOpRange&= ~KMMCOCRLowVoltage;
4418 s.FillCommandDesc(ECmdSendOpCond, (iCurrentOpRange | KMMCOCRAccessModeHCS | KMMCOCRBusy)); // Range supported + Busy bit (iArgument==KBit31)
4419 SMF_GOTOS( EStSetRangeLoop )
4422 // Interrogate card(s) present - issue CMD1 with omitted voltage range
4423 s.FillCommandDesc( ECmdSendOpCond, KMMCOCRAccessModeHCS | KMMCOCRBusy); // Full range + Sector Access + Busy bit (iArgument==KBit31)
4424 m.SetTraps( KMMCErrResponseTimeOut );
4426 SMF_INVOKES( ExecCommandSMST, EStFullRangeDone )
4428 SMF_STATE(EStFullRangeDone)
4430 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM4, "EStFullRangeDone" );
4431 if( err ) // If timeout
4433 iConfig.RemoveMode( KMMCModeEnableTimeOutRetry ); // There is no point to do it second time
4437 // Cards responded with Op range - evaluate the common subset with the current setting
4438 // Dont worry aboout the busy bit for now, we'll check that when we repeat the command
4439 TUint32 newrange = (TMMC::BigEndian32(s.ResponseP()) & ~KMMCOCRBusy);
4440 newrange &= iCurrentOpRange;
4444 // One or more card is incompatible with our h/w
4445 if (iMaxCardsInStack<=1)
4447 OstTraceFunctionExitExt( DMMCSTACK_ACQUIRESTACKSM_EXIT1, this, (TInt) KMMCErrNotSupported );
4448 return KMMCErrNotSupported; // There can only be one card - we don't support it.
4451 // Force the default range
4452 iCurrentOpRange=(psu->VoltageSupported() & ~KMMCAdjustableOpVoltage);
4455 iCurrentOpRange=newrange; // OK, new cards are compatible
4458 // If platform and the card both support low voltage mode (1.65 - 1.95v), switch
4459 if (iCurrentOpRange & KMMCOCRLowVoltage)
4461 iCurrentOpRange = KMMCOCRLowVoltage;
4462 SMF_INVOKES( SwitchToLowVoltageSMST, EStSetRangeLoop )
4465 SMF_STATE(EStSetRangeLoop)
4467 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM5, "EStSetRangeLoop" );
4468 // Repeat CMD1 this time setting Current Op Range
4469 s.Command().iArgument = iCurrentOpRange | KMMCOCRAccessModeHCS | KMMCOCRBusy;
4471 m.SetTraps( KMMCErrResponseTimeOut );
4473 SMF_INVOKES( ExecCommandSMST, EStSetRangeBusyCheck )
4475 SMF_STATE(EStSetRangeBusyCheck)
4477 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM6, "EStSetRangeLoop" );
4480 // Bit31 of the OCR response is low if the cards are still powering up.
4481 const TUint32 ocrResponse = TMMC::BigEndian32(s.ResponseP());
4483 const TBool isBusy = ((ocrResponse & KMMCOCRBusy) == 0);
4484 __KTRACE_OPT(KPBUS1,Kern::Printf("-mmc:upd:bsy%d", isBusy));
4485 OstTrace1( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM7, "MMC busy status=%d", isBusy );
4489 // Some cards are still busy powering up. Check if we should timeout
4490 if ( ++iCxPollRetryCount > iConfig.OpCondBusyTimeout() )
4492 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM8, "Peripheral bus timeout" );
4493 OstTraceFunctionExitExt( DMMCSTACK_ACQUIRESTACKSM_EXIT2, this, (TInt) KMMCErrBusTimeOut );
4494 return KMMCErrBusTimeOut;
4497 SMF_INVOKES( RetryGapTimerSMST, EStSetRangeLoop )
4502 if((ocrResponse & KMMCOCRAccessModeMask) == KMMCOCRAccessModeHCS)
4504 __KTRACE_OPT(KPBUS1, Kern::Printf("Found large MMC card."));
4505 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM9, "Found large MMC card" );
4506 iSpare[0] = KMMCardIsHighCapacity;
4510 iConfig.SetMode( EffectiveModes(s.iConfig) & KMMCModeEnableTimeOutRetry ); // Restore original setting
4512 // All cards are now ready and notified of the voltage range - ask ASSP to set it up
4513 psu->SetVoltage(iCurrentOpRange);
4514 if (psu->SetState(EPsuOnFull) != KErrNone)
4516 OstTraceFunctionExitExt( DMMCSTACK_ACQUIRESTACKSM_EXIT3, this, (TInt) KMMCErrHardware );
4517 return KMMCErrHardware;
4520 iCardArray->InitNewCardScan(); // Collect new cards, one by one
4522 SMF_STATE(EStCIDLoop)
4524 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM10, "EStCIDLoop" );
4525 if ( iCardArray->NewCardCount() >= iMaxCardsInStack )
4526 SMF_GOTOS( EStCIDsDone )
4528 s.FillCommandDesc( ECmdAllSendCID, 0 );
4529 m.SetTraps( KMMCErrResponseTimeOut );
4531 SMF_INVOKES( ExecCommandSMST, EStSendCIDIssued )
4533 SMF_STATE(EStSendCIDIssued)
4535 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM11, "EStSendCIDIssued" );
4538 // A card responded with a CID. Create a new card entry in the card array
4539 // and initialise this entry with the CID. The card array allocates it an
4540 // RCA, either the old RCA if we have seen this card before, or a new one.
4542 iCardArray->AddNewCard(s.ResponseP(),&rca); // Response is CID
4544 // Now assign the new RCA to the card
4545 s.FillCommandDesc( ECmdSetRelativeAddr, TMMCArgument(rca) );
4547 SMF_INVOKES( ExecCommandSMST, EStCIDLoop )
4550 SMF_STATE(EStCIDsDone)
4552 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM12, "EStCIDsDone" );
4553 // All cards are initialised; get all their CSDs
4554 m.ResetTraps(); // We are no longer processing any errors
4556 if( iCardArray->NewCardCount()==0 )
4557 SMF_EXIT // No new cards acquired
4559 iCxCardCount=0; // New cards index
4560 s.FillCommandDesc( ECmdSendCSD );
4562 SMF_STATE(EStCSDLoop)
4564 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM13, "EStCSDLoop" );
4565 s.Command().iArgument = TMMCArgument(iCardArray->NewCardP(iCxCardCount)->iRCA);
4566 SMF_INVOKES( ExecCommandSMST, EStSendCSDDone )
4568 SMF_STATE(EStSendCSDDone)
4570 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM14, "EStSendCSDDone" );
4571 // Store the CSD in the new card entry
4572 TMMCard* cardP = iCardArray->NewCardP(iCxCardCount);
4573 cardP->iCSD = s.ResponseP();
4575 // Perform MMC Specific parsing of the CSD structure
4576 TUint specVers = cardP->CSD().SpecVers(); // 1 => 1.4, 2 => 2.0 - 2.2, 3 => 3.1
4578 if ((specVers >= 2) && (cardP->CSD().CCC() & KMMCCmdClassLockCard))
4580 cardP->iFlags |= KMMCardIsLockable;
4583 if(iSpare[0] == KMMCardIsHighCapacity)
4585 cardP->iFlags |= KMMCardIsHighCapacity;
4588 if( ++iCxCardCount < (TInt)iCardArray->NewCardCount() )
4589 SMF_GOTOS( EStCSDLoop )
4591 SMF_NEXTS(EStMergeCards)
4593 SMF_STATE(EStMergeCards)
4595 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM15, "EStMergeCards" );
4596 // Merging the old card info with newly acquired cards (we will ask each card for status
4597 // to determine whether it's really present later).
4598 if( SchedGetOnDFC() )
4600 if ( iCardArray->MergeCards(ETrue)==KErrNone )
4601 SMF_EXIT // Completed successfully
4603 SMF_INVOKES( CheckStackSMST, EStReMergeCards ) // No space so check if any cards have gone
4605 SMF_STATE(EStReMergeCards)
4607 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ACQUIRESTACKSM16, "EStReMergeCards" );
4608 if( SchedGetOnDFC() )
4610 if ( iCardArray->MergeCards(EFalse)!=KErrNone ) // There are more cards in the stack than we can handle
4612 OstTraceFunctionExitExt( DMMCSTACK_ACQUIRESTACKSM_EXIT4, this, (TInt) KMMCErrTooManyCards );
4613 return KMMCErrTooManyCards;
4621 * Power down the bus and power it up again in low-voltage mode
4623 * @return MMC error code.
4625 TMMCErr DMMCStack::SwitchToLowVoltageSM()
4635 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:SwLowVolt"));
4637 DMMCPsu* psu=(DMMCPsu*)iSocket->iVcc;
4638 OstTrace1( TRACE_INTERNALS, DMMCSTACK_SWITCHTOLOWVOLTAGESM1, "Current PSU=0x%x", psu );
4641 OstTrace0( TRACE_INTERNALS, DMMCSTACK_SWITCHTOLOWVOLTAGESM2, "EStBegin" );
4644 psu->SetState(EPsuOff);
4646 // turn power back on in low voltage mode
4647 psu->SetVoltage(iCurrentOpRange);
4648 if (psu->SetState(EPsuOnFull) != KErrNone)
4650 OstTraceFunctionExitExt( DMMCSTACK_SWITCHTOLOWVOLTAGESM_EXIT, this, (TInt) KMMCErrHardware );
4651 return KMMCErrHardware;
4654 SMF_INVOKES( DoPowerUpSMST, EStPoweredUp )
4656 SMF_STATE(EStPoweredUp)
4657 OstTrace0( TRACE_INTERNALS, DMMCSTACK_SWITCHTOLOWVOLTAGESM3, "EStPoweredUp" );
4658 // turn the clock back on
4659 SMF_INVOKES( InitClockOnSMST, EStClockOn ) // Feed init clock to the bus
4661 SMF_STATE(EStClockOn)
4662 OstTrace0( TRACE_INTERNALS, DMMCSTACK_SWITCHTOLOWVOLTAGESM4, "EStClockOn" );
4663 // wait for 1ms and then 74 clock cycles
4664 // 74 clock cylces @ 400 Khz = 74 / 400,000 = 0.000185 secs = 0.185 ms
4665 // so total wait = 1.185 ms
4666 SMF_INVOKES(LowVoltagePowerupTimerSMST, EStEnd);
4672 inline TMMCErr DMMCStack::CIMCheckStackSM()
4674 * Performs the CIM_CHECK_STACK macro (with pre-emption disabled).
4675 * @return MMC error code
4685 DMMCSession& s=Session();
4686 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMCHECKSTACKSM1, "Current session=0x%x", &s );
4690 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMCHECKSTACKSM2, "EStBegin" );
4691 // This macro works naked and must not be preempted
4692 iConfig.RemoveMode( KMMCModeEnablePreemption | KMMCModeCardControlled );
4693 s.iState |= KMMCSessStateInProgress;
4695 SMF_INVOKES( CheckStackSMST, EStFinish )
4697 SMF_STATE(EStFinish)
4699 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMCHECKSTACKSM3, "EStFinish" );
4700 s.iState &= ~KMMCSessStateInProgress;
4705 inline TMMCErr DMMCStack::CheckStackSM()
4707 * For each card in iCards[], sends CMD13 to see if still there.
4708 * If not, calls DeclareCardAsGone(). Frees up space for new cards.
4709 * @return MMC error code
4716 EStCardSelectedGotStatus,
4721 DMMCSession& s=Session();
4722 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM1, "Current session=0x%x", &s );
4726 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM2, "EStBegin" );
4728 m.SetTraps( KMMCErrResponseTimeOut );
4732 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM3, "EStLoop" );
4733 if ( ++iCxCardCount == (TInt)iMaxCardsInStack )
4736 if ( !iCardArray->CardP(iCxCardCount)->IsPresent() )
4737 SMF_GOTOS( EStLoop ) // card's not present
4739 TUint32 arg = TUint32(iCardArray->CardP(iCxCardCount)->RCA()) << 16;
4740 s.FillCommandDesc(ECmdSelectCard, arg);
4741 SMF_INVOKES(ExecCommandSMST, EStCardSelectedGotStatus)
4743 SMF_STATE(EStCardSelectedGotStatus)
4745 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM4, "EStCardSelectedGotStatus" );
4746 __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:cssm:err%08x", err));
4747 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM5, "err=0x%08x", err );
4751 // Timeout - the card is no longer present so remove from the card array
4752 iCardArray->DeclareCardAsGone(iCxCardCount);
4753 SMF_GOTOS( EStLoop )
4756 TMMCard& card=*(iCardArray->CardP(iCxCardCount));
4757 card.iStatus=s.ResponseP();
4759 // This function is only called as part of the power up sequence, so
4760 // take the opportunity to record if it has a password
4761 if((card.iStatus & KMMCStatCardIsLocked) != 0)
4763 card.iFlags|=KMMCardHasPassword;
4766 s.FillCommandDesc(ECmdSelectCard, 0);
4767 SMF_INVOKES(ExecCommandSMST, EStCardDeselected)
4769 SMF_STATE(EStCardDeselected)
4770 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKSTACKSM6, "EStCardDeselected" );
4771 SMF_GOTOS( EStLoop )
4776 inline TMMCErr DMMCStack::CheckLockStatusSM()
4778 * Called as part of the power-up sequence, this determined if the card is locked or has a password.
4780 * If the card reports itself as being unlocked and there is a mapping in the password store,
4781 * then the stored password is used to attempt to lock the card. The overall aim of this is
4782 * to ensure that if a card always powers up in the locked state if it contains a known password.
4784 * This ensures that cards that are still unlocked after a power down/power up sequence do not
4785 * end up having their passwords removed from the store, which can happen in environments where
4786 * the PSU voltage level is not monitored - in such systems, we cannot guarantee that a card will
4787 * be fully reset and power up locked, hence the need to attempt to lock the card.
4789 * @return MMC error code
4796 EStCardSelectedGotStatus,
4802 DMMCSession& s=Session();
4803 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM1, "Current session=0x%x", &s );
4807 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM2, "EStBegin" );
4809 m.SetTraps( KMMCErrResponseTimeOut );
4810 iMinorBufLen = KMinMinorBufSize;
4814 if ( ++iCxCardCount == (TInt)iMaxCardsInStack )
4817 if ( !iCardArray->CardP(iCxCardCount)->IsPresent() )
4818 SMF_GOTOS( EStLoop ) // card's not present
4820 TUint32 arg = TUint32(iCardArray->CardP(iCxCardCount)->RCA()) << 16;
4821 s.FillCommandDesc(ECmdSelectCard, arg);
4822 SMF_INVOKES(ExecCommandSMST, EStCardSelectedGotStatus)
4824 SMF_STATE(EStCardSelectedGotStatus)
4826 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM3, "EStCardSelectedGotStatus" );
4827 __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:cssm:err%08x", err));
4828 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM4, "err=0x%08x", err );
4831 TMMCard& card=*(iCardArray->CardP(iCxCardCount));
4832 card.iStatus=s.ResponseP(); // Got the response
4834 iMinorBufLen = Max(iMinorBufLen, 1 << card.MaxReadBlLen());
4836 // this function is only called as part of the power up sequence, so
4837 // take the opportunity to record if it has a password
4838 if((card.iStatus & KMMCStatCardIsLocked) != 0)
4840 card.iFlags |= KMMCardHasPassword;
4843 // If the status suggests that the card is unlocked, we test
4844 // for the presence of a password by attempting to lock the card
4845 // (if we have a password in the store). This handles conditions
4846 // where a card has not been fully powered down before reapplying power.
4847 if(!(card.iFlags & KMMCardHasPassword))
4849 TMapping* pmp = iSocket->iPasswordStore->FindMappingInStore(card.CID());
4852 if(pmp->iState == TMapping::EStValid)
4854 const TInt kPWD_LEN = pmp->iPWD.Length();
4855 iPSLBuf[0] = KMMCLockUnlockLockUnlock; // LOCK_UNLOCK = 1, SET_PWD = 0, CLR_PWD = 0
4856 iPSLBuf[1] = static_cast<TUint8>(kPWD_LEN);
4857 TPtr8 pwd(&iPSLBuf[2], kPWD_LEN);
4858 pwd.Copy(pmp->iPWD);
4860 const TInt kBlockLen = 1 + 1 + kPWD_LEN;
4862 // Need to use CIMReadWriteBlocksSMST to ensure that the
4863 // card is connected and the block length is set correctly
4864 s.SetCard(iCardArray->CardP(iCxCardCount));
4865 m.SetTraps(KMMCErrStatus | KMMCErrUpdPswd);
4866 s.FillCommandDesc(ECmdLockUnlock);
4867 s.FillCommandArgs(0, kBlockLen, iPSLBuf, kBlockLen);
4869 TMMCCommandDesc& cmd = s.Command();
4870 cmd.iUnlockRetries = 0;
4872 SMF_INVOKES(CIMReadWriteBlocksSMST,EStCheckLockStatus)
4878 SMF_GOTOS( EStLoop )
4880 SMF_STATE(EStCheckLockStatus)
4882 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM5, "EStCheckLockStatus" );
4883 __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:cssm:err%08x", err));
4884 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM6, "err=0x%08x", err );
4886 if ((err & KMMCErrUpdPswd) ||
4887 ((err & KMMCErrStatus) && (s.LastStatus().Error() == KMMCStatErrLockUnlock)))
4889 // ECMDLockUnlock (with LockUnlockLockUnlock param) succeeded.
4890 // (either locked successfully, or we have attempted to lock a locked card)
4891 // Now determine if the card really is locked by checking the lock status.
4892 TMMCard& card=*(iCardArray->CardP(iCxCardCount));
4893 card.iStatus=s.LastStatus();
4894 if((card.iStatus & KMMCStatCardIsLocked) != 0)
4896 card.iFlags |= KMMCardHasPassword;
4900 s.FillCommandDesc(ECmdSelectCard, 0);
4901 SMF_INVOKES(ExecCommandSMST, EStCardDeselected)
4903 SMF_STATE(EStCardDeselected)
4904 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CHECKLOCKSTATUSSM7, "EStCardDeselected" );
4905 SMF_GOTOS( EStLoop )
4910 EXPORT_C TMMCErr DMMCStack::ModifyCardCapabilitySM()
4912 // This function provides a chance to modify the capability of paticular cards.
4913 // Licensee may overide this function to modify certain card's capability as needed.
4914 // A state machine is needed in derived function and function of base class should be
4915 // called in order to act more generic behaviour.
4933 inline TMMCErr DMMCStack::PollGapTimerSM()
4935 * Starts the poll timer.
4937 * This may be used when executing CIM_UPDATE_ACQ when handling cards which are
4938 * slow to power-up/reset and return busy following the issuing of CMD1.
4940 * @return MMC error code.
4949 DMMCSession& s=Session();
4950 OstTrace1( TRACE_INTERNALS, DMMCSTACK_POLLGAPTIMERSM1, "Current session=0x%x", &s );
4954 OstTrace0( TRACE_INTERNALS, DMMCSTACK_POLLGAPTIMERSM2, "EStBegin" );
4956 s.SynchBlock( KMMCBlockOnPollTimer );
4957 s.iPollTimer.OneShot(KMMCPollGapInMilliseconds,EFalse);
4965 inline TMMCErr DMMCStack::RetryGapTimerSM()
4967 * Starts the retry timer.
4969 * This may be used when executing CIM_UPDATE_ACQ. When initialising the stack,
4970 * CMD0 is issued twice to get the bus in a known state and this timer is used
4971 * to time the gap between issuing the two CMD0 commands.
4973 * @return MMC error code.
4982 DMMCSession& s=Session();
4983 OstTrace1( TRACE_INTERNALS, DMMCSTACK_RETRYGAPTIMERSM1, "Current session=0x%x", &s );
4987 OstTrace0( TRACE_INTERNALS, DMMCSTACK_RETRYGAPTIMERSM2, "EStBegin" );
4989 s.SynchBlock( KMMCBlockOnRetryTimer );
4990 s.iRetryTimer.OneShot(KMMCRetryGapInMilliseconds,EFalse);
4998 inline TMMCErr DMMCStack::ProgramTimerSM()
5000 * Starts the program timer.
5002 * This is used during write operartions to a card to sleep for an PSL-dependent period
5003 * between issuing send status commands (CMD13). This is required in order to check when
5004 * the card has finished writing its data to payload memory.
5006 * @return MMC error code.
5016 DMMCSession &s = Session();
5017 OstTrace1( TRACE_INTERNALS, DMMCSTACK_PROGRAMTIMERSM1, "Current session=0x%x", &s );
5021 OstTrace0( TRACE_INTERNALS, DMMCSTACK_PROGRAMTIMERSM2, "EStBegin" );
5023 s.SynchBlock(KMMCBlockOnPgmTimer);
5024 s.iProgramTimer.Cancel();
5025 s.iProgramTimer.OneShot(ProgramPeriodInMilliSeconds(),EFalse);
5032 TMMCErr DMMCStack::LowVoltagePowerupTimerSM()
5034 * Starts the low voltage power-up timer
5035 * NB Re-uses the retry gap timer.
5037 * This is used after powering the bus off and then on after discovering that
5038 * both the controller and card support low voltage operation.
5040 * @return MMC error code.
5050 DMMCSession &s = Session();
5051 OstTrace1( TRACE_INTERNALS, DMMCSTACK_LOWVOLTAGEPOWERUPTIMERSM1, "Current session=0x%x", &s );
5055 OstTrace0( TRACE_INTERNALS, DMMCSTACK_LOWVOLTAGEPOWERUPTIMERSM2, "EStBegin" );
5057 s.SynchBlock(KMMCBlockOnRetryTimer);
5058 s.iRetryTimer.OneShot(KMMCLowVoltagePowerUpTimeoutInMilliseconds,EFalse);
5066 inline TMMCErr DMMCStack::ExecCommandSM()
5068 * The main command executor.
5069 * Depending on the main command being issued, this macro may result in the issuing of whole sequence
5070 * of commands as it prepares the bus for the command in question.
5072 * In certain circumstances, this first issues one or more de-select commands (CMD7 + reserved RCA)
5073 * to get the bus in a known state. It then analyses the main command and if necessary, selects the
5074 * card in question (CMD7 + target RCA).
5076 * For block transfer commands, it will set the block length on the card concerned (CMD16) if this has
5077 * not been done already. Likewise, for SD Cards, if the bus width has not yet been set-up, it will issue
5078 * the appropriate bus width command (ACMD6).
5080 * Finally it issues the main command requested before performing any error recovery that may be necessary
5083 * In all cases it calls the generic layer child function IssueCommandCheckResponseSM() to execute each command.
5085 * @return MMC error code
5094 EStDeselectEndCheck,
5097 EStBlockCountCmdIssued,
5099 EStIssueAppCommandDone,
5106 DMMCSession& s=Session();
5107 OstTrace1( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM1, "Current session=0x%x", &s );
5111 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM2, "EStBegin" );
5112 if ( ( s.CardRCA() != 0 ) && ( (s.CardP()->iStatus.State()) == ECardStateSlp) )
5114 // Currently selected media is asleep, so it must be awoken
5115 SMF_INVOKES(ExecAwakeCommandSMST,EStExecCmd)
5118 SMF_STATE(EStExecCmd)
5120 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM3, "EStExecCmd" );
5121 TMMCCommandDesc& cmd = s.Command();
5122 // clearup some internally used flags
5123 cmd.iFlags &= ~(KMMCCmdFlagExecTopBusy|KMMCCmdFlagExecSelBusy);
5124 cmd.iPollAttempts = cmd.iTimeOutRetries = cmd.iCRCRetries = 0;
5128 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM4, "EStRetry" );
5129 TMMCCommandDesc& cmd = s.Command();
5130 m.SetTraps( KMMCErrBasic & ~Command().iExecNotHandle); // Processing all trappable errors
5132 if (iMultiplexedBus)
5134 if(cmd.iCommand == ECmdSelectCard)
5136 DeselectsToIssue(1);
5139 if (iConfig.iModes & KMMCModeCardControlled)
5141 DoSetBusWidth(BusWidthEncoding(s.CardP()->BusWidth()));
5142 DoSetClock(MaxTranSpeedInKilohertz(*s.CardP()));
5144 // Check if this card is already in the appropriate selected/deselected
5145 // state for the forthcoming command.
5146 if (s.CardRCA() != iSelectedCard)
5148 DeselectsToIssue(1);
5153 // If bus context is unknown, issue DESELECT a few times with a RetryGap between them.
5154 if ( (iStackState & KMMCStackStateDoDeselect) == 0 )
5155 SMF_GOTOS( EStAnalyseCommand )
5157 // Save the top-level command while we issue de-selects
5158 s.PushCommandStack();
5159 s.FillCommandDesc( ECmdSelectCard, 0 ); // Deselect - RCA=0
5160 iCxDeselectCount=iDeselectsToIssue;
5162 SMF_STATE(EStDeselectLoop)
5163 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM5, "EStDeselectLoop" );
5164 SMF_INVOKES(IssueCommandCheckResponseSMST,EStDeselectEndCheck)
5166 SMF_STATE(EStDeselectEndCheck)
5168 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM6, "EStDeselectEndCheck" );
5169 // If we got an error and this is the last de-select then give up
5170 if (err && iCxDeselectCount == 1)
5172 s.PopCommandStack();
5173 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT1, this, (TInt) err );
5177 if (--iCxDeselectCount > 0)
5178 SMF_INVOKES(RetryGapTimerSMST,EStDeselectLoop)
5180 s.PopCommandStack();
5181 iStackState &= ~KMMCStackStateDoDeselect;
5183 SMF_STATE(EStAnalyseCommand)
5185 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM7, "EStAnalyseCommand" );
5186 TMMCCommandDesc& cmd = s.Command();
5187 // Check if its un-important whether the card is in transfer state (i.e
5188 // selected) or not for the command we are about to execute. Such
5189 // commands are CMD0, CMD7 and CMD13.
5191 // This state machine should never send CMD55
5192 if (cmd.iCommand == ECmdAppCmd)
5194 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT2, this, (TInt) KMMCErrNotSupported );
5195 SMF_RETURN (KMMCErrNotSupported)
5198 SMF_NEXTS( EStTestAppCommand )
5199 if (cmd.iCommand == ECmdGoIdleState || cmd.iCommand == ECmdSelectCard || cmd.iCommand == ECmdSendStatus)
5204 // See if we need to select (or deselect) this card
5206 switch( cmd.iSpec.iCommandType )
5208 case ECmdTypeBC: case ECmdTypeBCR: case ECmdTypeAC:
5209 // Command which don't require the card to be selected
5211 case ECmdTypeACS: case ECmdTypeADTCS: case ECmdTypeADC:
5212 // Commands which do require the card to be selected
5214 if ( (iConfig.iModes & KMMCModeCardControlled) == 0 )
5216 // Get the RCA of the card
5217 if ( (targetRCA = s.CardRCA()) == 0 )
5219 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT3, this, (TInt) KMMCErrNoCard );
5220 SMF_RETURN( KMMCErrNoCard )
5228 // Check if this card is already in the appropriate selected/deselected
5229 // state for the forthcoming command.
5230 if (targetRCA==iSelectedCard)
5233 // Need to select (or deselect by using RCA(0)) the card so push the
5234 // top-level command onto the command stack while we issue the select command.
5235 s.PushCommandStack();
5236 s.FillCommandDesc(ECmdSelectCard,targetRCA);
5237 SMF_INVOKES(IssueCommandCheckResponseSMST,EStSelectDone)
5239 SMF_STATE(EStSelectDone)
5241 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM8, "EStSelectDone" );
5242 TMMCCommandDesc& cmd = s.Command();
5246 cmd.iFlags &= ~(KMMCCmdFlagASSPFlags|KMMCCmdFlagExecSelBusy);
5248 if (err == KMMCErrBusyTimeOut)
5249 cmd.iFlags |= KMMCCmdFlagExecSelBusy;
5251 s.PopCommandStack();
5252 SMF_NEXTS(EStErrRecover)
5253 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT4, this, (TInt) err );
5254 return err; // re-enter the next state with that error
5257 // Are we trying to recover from a top-level command returning busy (by de-selecting and re-selecting)
5258 if ( cmd.iFlags & KMMCCmdFlagExecTopBusy )
5260 cmd.iFlags &= ~KMMCCmdFlagExecTopBusy;
5262 TUint32 blockLength = cmd.BlockLength();
5264 if ( !(cmd.iSpec.iMultipleBlocks) || cmd.iTotalLength <= blockLength )
5265 SMF_EXIT // operation is completed
5267 cmd.iTotalLength -= blockLength;
5268 cmd.iArgument = TUint(cmd.iArgument) + blockLength;
5269 cmd.iDataMemoryP += blockLength;
5270 s.iBytesTransferred += blockLength;
5271 cmd.iPollAttempts = 0;
5274 s.PopCommandStack();
5277 if (!cmd.iSpec.iUseStopTransmission && cmd.iSpec.iMultipleBlocks)
5279 // Multi-block command using SET_BLOCK_COUNT
5280 // This is a re-try of the data transfer, normally select (CMD7) is performed along with the issuing of CMD23,
5281 // therefore need to re-issue SET_BLOCK_COUNT.....
5282 const TUint blocks = cmd.NumBlocks();
5284 s.PushCommandStack();
5285 s.FillCommandDesc( ECmdSetBlockCount, blocks );
5286 SMF_INVOKES( IssueCommandCheckResponseSMST, EStBlockCountCmdIssued )
5290 SMF_GOTOS( EStTestAppCommand )
5293 SMF_STATE(EStBlockCountCmdIssued)
5295 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM9, "EStBlockCountCmdIssued" );
5296 const TMMCStatus status(s.ResponseP());
5297 s.PopCommandStack();
5300 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT5, this, (TInt) KMMCErrStatus );
5301 SMF_RETURN(KMMCErrStatus)
5304 if(err & KMMCErrNotSupported)
5306 // Not supported by the PSL, so use standard Stop Transmission mode
5307 s.Command().iSpec.iUseStopTransmission = ETrue;
5311 SMF_STATE(EStTestAppCommand)
5312 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM10, "EStTestAppCommand" );
5313 TMMCCommandDesc& cmd = s.Command();
5314 if (cmd.iSpec.iCommandClass != KMMCCmdClassApplication)
5315 SMF_GOTOS( EStIssueCommand )
5317 s.PushCommandStack();
5318 s.FillCommandDesc(ECmdAppCmd, s.CardRCA()); // Send APP_CMD (CMD55)
5319 SMF_INVOKES(IssueCommandCheckResponseSMST,EStIssueAppCommandDone)
5321 SMF_STATE(EStIssueAppCommandDone)
5322 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM11, "EStIssueAppCommandDone" );
5323 s.PopCommandStack();
5326 SMF_NEXTS(EStErrRecover)
5327 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT6, this, (TInt) err );
5328 return err; // re-enter the next state with that error
5332 SMF_STATE(EStIssueCommand)
5334 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM12, "EStIssueCommand" );
5335 TMMCCommandDesc& cmd = s.Command();
5336 // If its an addressed command (rather than a selected command), then
5337 // setup the argument with the RCA. (Commands requiring card to be
5338 // selected - ACS don't matter since selected cards don't need an RCA now).
5339 if ((iConfig.iModes & KMMCModeCardControlled) && cmd.iSpec.iCommandType==ECmdTypeAC )
5341 const TRCA targetRCA = s.CardRCA();
5342 if ( targetRCA == 0 )
5344 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT7, this, (TInt) KMMCErrNoCard );
5345 SMF_RETURN( KMMCErrNoCard )
5347 cmd.iArgument.SetRCA(targetRCA);
5350 // Issue the top-level command
5351 SMF_INVOKES(IssueCommandCheckResponseSMST,EStCommandIssued)
5353 SMF_STATE(EStCommandIssued)
5355 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM13, "EStCommandIssued" );
5356 // If command was succesful then we've finished.
5360 SMF_STATE(EStErrRecover)
5362 OstTrace0( TRACE_INTERNALS, DMMCSTACK_EXECCOMMANDSM14, "EStErrRecover" );
5363 TMMCCommandDesc& cmd = s.Command();
5364 const TUint32 modes=iConfig.iModes;
5367 m.ResetTraps(); // no more re-entries via return()
5369 if (cmd.iCommand == ECmdSelectCard)
5370 DeselectsToIssue( 1 ); // in case stby/tran synch is lost
5372 if (cmd.iSpec.iMultipleBlocks && (cmd.iFlags & KMMCCmdFlagBytesValid))
5374 cmd.iTotalLength -= cmd.iBytesDone;
5375 cmd.iArgument = TUint(cmd.iArgument) + cmd.iBytesDone;
5376 cmd.iDataMemoryP += cmd.iBytesDone;
5377 s.iBytesTransferred += cmd.iBytesDone;
5379 if (cmd.iTotalLength < cmd.BlockLength())
5381 DeselectsToIssue(1);
5382 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT8, this, (TInt) err );
5387 if ((modes & KMMCModeEnableRetries) == 0)
5389 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT9, this, (TInt) err );
5393 const TUint32 toMask = (KMMCErrResponseTimeOut|KMMCErrDataTimeOut);
5394 const TUint32 crcMask = (KMMCErrResponseCRC|KMMCErrDataCRC|KMMCErrCommandCRC);
5396 if( (err & ~(toMask|crcMask)) == KMMCErrNone ) // time-outs/CRC errors
5398 if( cmd.iSpec.iCommandType == ECmdTypeADTCS ) // for data transfer commands
5400 DeselectsToIssue( 1 ); // enforce deselect before any retries
5402 if( (modes & KMMCModeCardControlled) == 0 )
5404 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT10, this, (TInt) err );
5405 return err; // we wouldn't know what to select - no retries
5409 TUint32 gapEnabled = 0;
5413 cmd.iTimeOutRetries++;
5414 gapEnabled |= KMMCModeTimeOutRetryGap;
5416 if( (modes & KMMCModeEnableTimeOutRetry) == 0 ||
5417 cmd.iTimeOutRetries > iConfig.iTimeOutRetries )
5419 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT11, this, (TInt) err );
5427 gapEnabled |= KMMCModeCRCRetryGap;
5429 if( (modes & KMMCModeEnableCRCRetry) == 0 ||
5430 cmd.iCRCRetries > iConfig.iCRCRetries ||
5431 ((err & KMMCErrDataCRC) != 0 && (modes & KMMCModeDataCRCRetry) == 0) )
5433 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT12, this, (TInt) err );
5438 if( (modes & gapEnabled) == gapEnabled )
5440 if( modes & KMMCModeCardControlled )
5441 s.iState |= KMMCSessStateSafeInGaps; // preemption allowed
5443 SMF_CALL( RetryGapTimerSMST )
5446 if( (modes & (KMMCModeEnablePreemption|KMMCModePreemptOnRetry|KMMCModeCardControlled)) ==
5447 (KMMCModeEnablePreemption|KMMCModePreemptOnRetry|KMMCModeCardControlled) )
5450 SMF_WAIT // let the others take over the bus before retry
5453 // No preemption, just repeat the command
5457 if( err & KMMCErrBusInconsistent )
5459 // ASSP layer reported that we must re-initialise the stack to recover.
5460 // Here we'll allow stack initialiser to take over. The control will then be transferred
5461 // to whoever processes KMMCErrInitContext (must be a top-level SM function)
5463 // ReportInconsistentBusState(); // ASSP layer should have it done
5466 if( s.iGlobalRetries > KMMCMaxGlobalRetries )
5468 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT13, this, (TInt) err );
5472 s.SwapMe(); // To prevent the initialiser from aborting this session
5473 SMF_WAIT // Initialiser will take over here
5476 if( err == KMMCErrBusyTimeOut )
5478 if ((cmd.iFlags & KMMCCmdFlagExecSelBusy) == 0) // check if that was a response
5479 cmd.iFlags |= KMMCCmdFlagExecTopBusy; // to a top level command
5481 DeselectsToIssue( 1 ); // force deselect as the next bus operation
5482 cmd.iPollAttempts++;
5484 if( (modes & KMMCModeEnableBusyPoll) == 0 ||
5485 ((modes & KMMCModeCardControlled) == 0 && cmd.iCommand != ECmdSelectCard) ||
5486 cmd.iPollAttempts > iConfig.iPollAttempts )
5488 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT14, this, (TInt) err );
5492 if( modes & KMMCModeBusyPollGap )
5494 s.iState |= KMMCSessStateSafeInGaps; // preemption allowed
5495 SMF_CALL( PollGapTimerSMST )
5498 if( (modes & (KMMCModeEnablePreemption|KMMCModePreemptOnBusy)) ==
5499 (KMMCModeEnablePreemption|KMMCModePreemptOnBusy) )
5502 SMF_WAIT // let the others take over the bus before retry
5505 // No preemption, just repeat the Deselect/Select sequence
5509 OstTraceFunctionExitExt( DMMCSTACK_EXECCOMMANDSM_EXIT15, this, (TInt) err );
5515 TMMCErr DMMCStack::IssueCommandCheckResponseSM()
5517 * Issue a single command to the card and check the response
5519 * This generic layer child function in turn calls IssueMMCCommandSM().
5521 * @return MMC error code.
5532 DMMCSession& s=Session();
5533 TMMCCommandDesc& cmd = Command();
5534 OstTrace1( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM1, "Current session=0x%x", &s );
5538 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM2, "EStBegin" );
5539 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Issue %d %x",TUint(cmd.iCommand),TUint(cmd.iArgument)));
5540 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM3, "CMD%02d(0x%08x)", TUint(cmd.iCommand), TUint(cmd.iArgument) );
5542 // Stop the Controller from powering down the card due to bus inactivity
5543 iSocket->ResetInactivity(0);
5545 SMF_STATE(EStIssueCommand)
5547 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM4, "EStIssueCommand" );
5548 // If command is directed at a specific card then save this command in card object
5549 if (iConfig.iModes & KMMCModeCardControlled)
5551 s.iCardP->iLastCommand = cmd.iCommand;
5555 DoSetBusWidth(BusWidthEncoding(s.CardP()->BusWidth()));
5556 DoSetClock(MaxTranSpeedInKilohertz(*s.CardP()));
5560 if (cmd.iCommand==ECmdSelectCard)
5561 iSelectedCard = TUint16(~0);
5563 // Pass the command to ASSP layer
5564 cmd.iFlags &= ~(KMMCCmdFlagASSPFlags|KMMCCmdFlagExecSelBusy);
5566 m.SetTraps(KMMCErrAll);
5567 SMF_INVOKES(IssueMMCCommandSMST,EStCommandIssued)
5569 SMF_STATE(EStCommandIssued)
5571 OstTrace0( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM5, "EStCommandIssued" );
5572 #ifdef ENABLE_DETAILED_SD_COMMAND_TRACE
5573 cmd.Dump(s.ResponseP(), err);
5576 OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM6, "MMC Protocol: CMD%02d(0x%08x)", (TInt) cmd.iCommand, (TUint) cmd.iArgument );
5577 OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM7, "MMC Protocol: RSP%d - LEN 0x%08x - ERR 0x%08x - STAT 0x%08x", (TUint) cmd.iSpec.iResponseType, (TUint) cmd.iSpec.iResponseLength, (TUint) err, (TUint) TMMC::BigEndian32(s.ResponseP()) );
5579 TMMCErr exitCode=err;
5580 // If we have just de-selected all cards in the stack, RCA(0) then ignore response timeout.
5581 if ( cmd.iCommand==ECmdSelectCard && TRCA(cmd.iArgument)==0 )
5582 exitCode &= ~KMMCErrResponseTimeOut;
5585 // If commands returns card status and there we no command errors
5586 // (or the status contains errors) then save the status info.
5587 if ( (cmd.iFlags & KMMCCmdFlagStatusReceived) ||
5588 ((exitCode==KMMCErrNone || (exitCode & KMMCErrStatus)) &&
5589 (cmd.iSpec.iResponseType==ERespTypeR1 || cmd.iSpec.iResponseType==ERespTypeR1B)) )
5591 TMMCStatus status=s.ResponseP();
5592 s.iLastStatus=status;
5593 __KTRACE_OPT(KPBUS1, Kern::Printf("mmc:ec:st=%08x", TUint32(status)));
5594 OstTrace1( TRACE_INTERNALS, DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM8, "status=0x%08x", TUint32(status) );
5596 if (iConfig.iModes & KMMCModeCardControlled)
5597 s.iCardP->iStatus=status;
5599 // Update exit code if card status is reporting an error (in case not done already)
5600 if (status.Error() != 0)
5601 exitCode |= KMMCErrStatus;
5605 // If we've just selected a card and the command was succesful then
5606 // remember which one so we don't need to do it twice.
5607 if (cmd.iCommand==ECmdSelectCard && exitCode==KMMCErrNone)
5608 iSelectedCard=TRCA(cmd.iArgument);
5610 OstTraceFunctionExitExt( DMMCSTACK_ISSUECOMMANDCHECKRESPONSESM_EXIT, this, ( TInt ) exitCode );
5611 SMF_RETURN(exitCode)
5617 // General Client Service CIMs/Sessions; top level functions
5619 inline TMMCErr DMMCStack::NakedSessionSM()
5621 * Executes an individual MMC command (as opposed to a macro).
5623 * If the command is 'card controlled' it first invokes AttachCardSM()
5624 * before calling ExecCommandSM() to excecute the requested command.
5626 * @return MMC error code.
5637 DMMCSession& s=Session();
5638 OstTrace1( TRACE_INTERNALS, DMMCSTACK_NAKEDSESSIONSM1, "Current session=0x%x", &s );
5641 OstTrace0( TRACE_INTERNALS, DMMCSTACK_NAKEDSESSIONSM2, "EStBegin" );
5642 s.iState |= KMMCSessStateInProgress;
5644 if( (iConfig.iModes & KMMCModeCardControlled) != 0 )
5645 SMF_INVOKES( AttachCardSMST, EStAttached )
5647 SMF_BPOINT(EStAttached)
5649 OstTrace0( TRACE_INTERNALS, DMMCSTACK_NAKEDSESSIONSM3, "EStAttached" );
5650 SMF_INVOKES( ExecCommandSMST, EStFinish )
5652 SMF_STATE(EStFinish)
5654 OstTrace0( TRACE_INTERNALS, DMMCSTACK_NAKEDSESSIONSM4, "EStFinish" );
5655 s.iState &= ~KMMCSessStateInProgress;
5659 inline TMMCErr DMMCStack::CIMSetupCardSM()
5661 * Executes the CIM_SETUP_CARD macro.
5663 * @return MMC error code.
5675 DMMCSession& s=Session();
5676 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM1, "Current session=0x%x; Last status=0x%x", (TUint) &s, (TUint) s.iLastStatus );
5678 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:SetupCardSM %x",TUint(s.iLastStatus)));
5682 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM2, "EStBegin" );
5683 s.iState |= KMMCSessStateInProgress;
5685 SMF_INVOKES( AttachCardSMST, EStAttached ) // attachment is mandatory here
5687 SMF_BPOINT(EStAttached)
5689 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM3, "EStAttached" );
5690 s.FillCommandDesc( ECmdSelectCard, 0 );
5691 SMF_INVOKES( ExecCommandSMST, EStSelected )
5693 SMF_STATE(EStSelected)
5695 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM4, "EStSelected" );
5696 if( !s.iCardP->IsReady() )
5698 OstTraceFunctionExitExt( DMMCSTACK_CIMSETUPCARDSM_EXIT, this, (TInt) KMMCErrNoCard );
5699 return KMMCErrNoCard;
5702 s.FillCommandDesc( ECmdSendCSD, Command().iArgument ); // NB: the card will be deselected to execute this command
5703 SMF_INVOKES( ExecCommandSMST, EStGotCSD )
5705 SMF_STATE(EStGotCSD)
5707 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMSETUPCARDSM5, "EStGotCSD" );
5708 s.iCardP->iCSD = s.ResponseP();
5710 s.iState &= ~KMMCSessStateInProgress;
5714 EXPORT_C TMMCErr DMMCStack::CIMReadWriteBlocksSM()
5716 * This macro performs single/multiple block reads and writes.
5718 * For normal read/write block operations, this function determines the appropriate
5719 * MMC command to send and fills the command descriptor accordingly based on
5720 * the value of the session ID set. However, it is necessary to have set the
5721 * command arguments (with DMMCSession::FillCommandArgs()) before this function
5724 * For special block read/write operations, e.g. lock/unlock, it is required to
5725 * have already filled the command descriptor (with DMMCSession::FillCommandDesc())
5726 * for the special command required - in addition to have setup the command arguments.
5728 * @return MMC error code.
5740 EStBlockCountCmdIssued,
5749 DMMCSession& s=Session();
5750 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM1, "Current session=0x%x; Last status=0x%x", (TUint) &s, (TUint) s.iLastStatus );
5752 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:RWBlocksSM %x",TUint(s.iLastStatus)));
5756 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM2, "EStBegin" );
5757 if(s.iSessionID == ECIMWriteBlock || s.iSessionID == ECIMWriteMBlock)
5759 // Check that the card supports class 4 (Write) commands
5760 const TUint ccc = s.iCardP->CSD().CCC();
5761 if(!(ccc & KMMCCmdClassBlockWrite))
5763 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT1, this, (TInt) KMMCErrNotSupported );
5764 return KMMCErrNotSupported;
5768 s.iState |= KMMCSessStateInProgress;
5769 m.SetTraps(KMMCErrInitContext);
5771 SMF_STATE(EStRestart) // NB: ErrBypass is not processed here
5773 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM3, "EStRestart" );
5774 SMF_CALLMEWR(EStRestart) // Create a recursive call entry to recover from the errors trapped
5775 m.SetTraps(KMMCErrStatus);
5776 if (s.Command().iSpec.iCommandClass!=KMMCCmdClassApplication || s.Command().iCommand==ECmdAppCmd)
5778 s.ResetCommandStack();
5779 SMF_INVOKES( AttachCardSMST, EStAttached ) // attachment is mandatory here
5782 SMF_BPOINT(EStAttached)
5784 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM4, "EStAttached" );
5785 TMMCCommandDesc& cmd = s.Command();
5787 const TUint32 blockLength = cmd.BlockLength();
5788 if(blockLength == 0)
5790 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT2, this, (TInt) KMMCErrArgument );
5791 return KMMCErrArgument;
5794 if(s.iSessionID == ECIMReadBlock ||
5795 s.iSessionID == ECIMWriteBlock ||
5796 s.iSessionID == ECIMReadMBlock ||
5797 s.iSessionID == ECIMWriteMBlock)
5799 // read/write operation
5800 if(!cmd.AdjustForBlockOrByteAccess(s))
5802 // unable to convert command arguments to suit the underlying block/byte access mode
5803 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT3, this, (TInt) KMMCErrArgument );
5804 return KMMCErrArgument;
5808 // Set the block length if it has changed. Always set for ECIMLockUnlock.
5809 if ((blockLength == s.iCardP->iSetBlockLen) && (s.iSessionID != ECIMLockUnlock))
5811 SMF_GOTOS( EStLengthSet )
5814 s.iCardP->iSetBlockLen = 0;
5815 s.PushCommandStack();
5816 s.FillCommandDesc( ECmdSetBlockLen, blockLength );
5817 SMF_INVOKES( ExecCommandSMST, EStLength1 )
5819 SMF_STATE(EStLength1)
5821 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM5, "EStAttached" );
5822 const TMMCStatus status(s.ResponseP());
5823 s.PopCommandStack();
5826 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT4, this, (TInt) KMMCErrStatus );
5827 SMF_RETURN(KMMCErrStatus)
5829 s.iCardP->iSetBlockLen = s.Command().BlockLength();
5831 SMF_STATE(EStLengthSet)
5833 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM6, "EStLengthSet" );
5834 TMMCCommandDesc& cmd = s.Command();
5836 const TUint kTypeWrite = KBit0;
5837 const TUint kTypeMultiple = KBit1;
5838 const TUint kTypeSpecial = KBit2;
5839 static const TMMCCommandEnum cmdCodes[4] =
5840 {ECmdReadSingleBlock, ECmdWriteBlock, ECmdReadMultipleBlock, ECmdWriteMultipleBlock};
5842 switch( s.iSessionID )
5846 case ECIMWriteBlock:
5849 case ECIMReadMBlock:
5850 opType=kTypeMultiple;
5852 case ECIMWriteMBlock:
5853 opType=kTypeWrite|kTypeMultiple;
5855 case ECIMLockUnlock:
5857 opType=kTypeSpecial;
5861 const TUint blocks = cmd.NumBlocks();
5863 SMF_NEXTS(EStBpoint1)
5864 if ( !(opType & kTypeSpecial) ) // A special session has already set its command descriptor
5867 if (cmd.iFlags & KMMCCmdFlagReliableWrite)
5868 //ensure multiple block commands are used for reliable writing
5869 opType |= kTypeMultiple;
5871 if ( (blocks==1) && !(cmd.iFlags & KMMCCmdFlagReliableWrite) )
5873 // Reliable Write requires that Multi-Block command is used.
5874 opType &= ~kTypeMultiple;
5877 TUint32 oldFlags = cmd.iFlags; // Maintain old flags which would be overwritten by FillCommandDesc
5878 cmd.iCommand = cmdCodes[opType];
5879 s.FillCommandDesc();
5880 cmd.iFlags = oldFlags; // ...and restore
5882 if((opType & kTypeMultiple) == kTypeMultiple)
5885 // This is a Multiple-Block DT command. Check the version of the card, as
5886 // MMC Version 3.1 onwards supports the SET_BLOCK_COUNT mode for DT.
5888 // Note that if the PSL does not support pre-determined block count of
5889 // data transmission, then it may return KMMCErrNotSupported to force
5890 // the 'Stop Transmission' mode to be used instead.
5892 if(s.iCardP->CSD().SpecVers() >= 3)
5894 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM7, "CMD12 (STOP_TRANSMISSION) not used" );
5896 cmd.iSpec.iUseStopTransmission = EFalse;
5897 SMF_NEXTS(EStIssueBlockCount)
5901 cmd.iSpec.iUseStopTransmission = ETrue;
5908 SMF_STATE(EStIssueBlockCount)
5909 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM8, "EStIssueBlockCount" );
5911 // Issues SET_BLOCK_COUNT (CMD23) for MB R/W data transfers.
5912 // This is only issued if MMC version >= 3.1 and the PSL
5913 // supports this mode of operation.
5915 TMMCCommandDesc& cmd = s.Command();
5916 TUint32 args = (TUint16)cmd.NumBlocks();
5918 m.SetTraps(KMMCErrStatus | KMMCErrNotSupported);
5920 if (cmd.iFlags & KMMCCmdFlagReliableWrite)
5922 // Command marked as Reliable Write
5923 // set Bit31 in CMD23 argument
5924 args |= KMMCCmdReliableWrite;
5927 s.PushCommandStack();
5928 s.FillCommandDesc( ECmdSetBlockCount, args );
5929 SMF_INVOKES( ExecCommandSMST, EStBlockCountCmdIssued )
5931 SMF_STATE(EStBlockCountCmdIssued)
5933 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM9, "EStBlockCountCmdIssued" );
5934 const TMMCStatus status(s.ResponseP());
5935 s.PopCommandStack();
5938 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT5, this, (TInt) KMMCErrStatus );
5939 SMF_RETURN(KMMCErrStatus)
5942 if(err & KMMCErrNotSupported)
5944 // Not supported by the PSL, so use standard Stop Transmission mode
5945 s.Command().iSpec.iUseStopTransmission = ETrue;
5948 SMF_GOTOS(EStBpoint1)
5950 SMF_STATE(EStAppCmdIssued)
5952 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM10, "EStAppCmdIssued" );
5953 const TMMCStatus status(s.ResponseP());
5954 s.PopCommandStack();
5957 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT6, this, (TInt) KMMCErrStatus );
5958 SMF_RETURN(KMMCErrStatus)
5961 SMF_BPOINT(EStBpoint1)
5963 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM11, "EStBpoint1" );
5964 // NB We need to trap KMMCErrStatus errors, because if one occurs,
5965 // we still need to wait to exit PRG/RCV/DATA state
5966 m.SetTraps(KMMCErrStatus);
5968 SMF_INVOKES( ExecCommandSMST, EStIssued )
5970 SMF_STATE(EStIssued)
5972 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM12, "EStIssued" );
5973 // check state of card after data transfer with CMD13.
5975 if (s.Command().Direction() != 0)
5977 SMF_GOTOS(EStWaitFinish)
5980 SMF_GOTOS(EStRWFinish);
5982 SMF_STATE(EStWaitFinish)
5984 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM13, "EStWaitFinish" );
5985 // Save the status and examine it after issuing CMD13...
5986 // NB We don't know where in the command stack the last response is stored (e.g. there may
5987 // have bee a Deselect/Select issued), but we do know last response is stored in iLastStatus
5988 TMMC::BigEndian4Bytes(s.ResponseP(), s.iLastStatus);
5990 s.PushCommandStack();
5991 s.FillCommandDesc(ECmdSendStatus, 0);
5992 SMF_INVOKES(ExecCommandSMST, EStWaitFinish1)
5994 SMF_STATE(EStWaitFinish1)
5995 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM14, "EStWaitFinish1" );
5996 const TMMCStatus status(s.ResponseP());
5997 s.PopCommandStack();
6000 SMF_GOTOS(EStRWFinish);
6002 const TMMCardStateEnum st1 = status.State();
6003 if (st1 == ECardStatePrg || st1 == ECardStateRcv || st1 == ECardStateData)
6005 SMF_INVOKES(ProgramTimerSMST, EStWaitFinish);
6009 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT7, this, (TInt) KMMCErrStatus );
6010 SMF_RETURN(KMMCErrStatus)
6014 // Fall through if CURRENT_STATE is not PGM or DATA
6015 SMF_STATE(EStRWFinish)
6017 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM15, "EStRWFinish" );
6018 if (TMMCStatus(s.ResponseP()).Error() != 0)
6020 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT8, this, (TInt) KMMCErrStatus );
6021 SMF_RETURN(KMMCErrStatus);
6024 s.iState &= ~KMMCSessStateInProgress;
6026 // skip over recursive entry or throw error and catch in CIMLockUnlockSM()
6027 TMMCErr ret = (s.Command().iCommand == ECmdLockUnlock) ? KMMCErrUpdPswd : KMMCErrBypass;
6028 OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT9, this, (TInt) ret );
6034 inline TMMCErr DMMCStack::CIMEraseSM()
6036 * This macro performs sector/group erase of a continuous area
6038 * @return MMC error code.
6055 DMMCSession& s=Session();
6056 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_CIMERASESM1, "Current session=0x%x; Last status=0x%x", (TUint) &s, (TUint) s.iLastStatus );
6059 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:EraseSM %x",TUint(s.iLastStatus)));
6063 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM2, "EStBegin" );
6064 // Check that the card supports class 4 (Write) commands
6065 const TUint ccc = s.iCardP->CSD().CCC();
6066 if(!(ccc & KMMCCmdClassErase))
6068 OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT1, this, (TInt) KMMCErrNotSupported );
6069 return KMMCErrNotSupported;
6072 s.iState |= KMMCSessStateInProgress;
6073 m.SetTraps( KMMCErrInitContext );
6075 SMF_STATE(EStRestart)
6077 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM3, "EStRestart" );
6078 SMF_CALLMEWR(EStRestart) // Create a recursive call entry to recover from Init
6080 s.ResetCommandStack();
6081 SMF_INVOKES( AttachCardSMST, EStAttached ) // attachment is mandatory
6083 SMF_BPOINT(EStAttached)
6085 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM4, "EStAttached" );
6086 TMMCCommandDesc& cmd = s.Command();
6088 if(cmd.iTotalLength == 0)
6090 OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT2, this, (TInt) KMMCErrArgument );
6091 return KMMCErrArgument;
6094 switch( s.iSessionID )
6096 case ECIMEraseSector:
6097 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM5, "ECIMEraseSector" );
6098 TMMCEraseInfo eraseInfo;
6099 s.iCardP->GetEraseInfo(eraseInfo);
6100 cmd.iBlockLength = eraseInfo.iMinEraseSectorSize;
6101 cmd.iCommand = ECmdTagSectorStart;
6103 case ECIMEraseGroup:
6104 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM6, "ECIMEraseGroup" );
6105 cmd.iBlockLength = s.iCardP->iCSD.EraseGroupSize();
6106 if(cmd.iBlockLength == 0 || cmd.iTotalLength % cmd.iBlockLength != 0)
6108 OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT3, this, (TInt) KMMCErrArgument );
6109 return KMMCErrArgument;
6111 cmd.iCommand = ECmdTagEraseGroupStart;
6114 DMMCSocket::Panic(DMMCSocket::EMMCEraseSessionID);
6117 if(!cmd.AdjustForBlockOrByteAccess(s))
6119 OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT4, this, (TInt) KMMCErrArgument );
6120 return KMMCErrArgument;
6123 iConfig.RemoveMode( KMMCModeEnablePreemption ); // erase sequence must not be pre-empted
6125 const TUint flags = cmd.iFlags;
6126 s.FillCommandDesc();
6128 SMF_INVOKES( ExecCommandSMST, EStStartTagged )
6130 SMF_STATE(EStStartTagged)
6132 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM7, "EStStartTagged" );
6133 const TMMCCommandDesc& cmd = s.Command();
6135 TMMCCommandEnum command;
6136 TUint endAddr = cmd.iArgument;
6137 if(s.iSessionID == ECIMEraseSector)
6139 endAddr += cmd.IsBlockCmd() ? (cmd.iTotalLength / cmd.iBlockLength - 1) : (cmd.iTotalLength - cmd.iBlockLength);
6140 command = ECmdTagSectorEnd;
6144 if(cmd.IsBlockCmd())
6146 endAddr += (cmd.iTotalLength - cmd.iBlockLength) >> KMMCardHighCapBlockSizeLog2;
6150 endAddr += cmd.iTotalLength - cmd.iBlockLength;
6153 command = ECmdTagEraseGroupEnd;
6156 s.PushCommandStack();
6157 s.FillCommandDesc( command, endAddr );
6158 SMF_INVOKES( ExecCommandSMST, EStEndTagged )
6160 SMF_STATE(EStEndTagged)
6162 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM8, "EStEndTagged" );
6163 // Increase the inactivity timeout as an erase operation can potentially take a long time
6164 // At the moment this is a somewhat arbitrary 30 seconds. This could be calculated more accurately
6165 // using TAAC,NSAC, R2W_FACTOR etc. but that seems to yield very large values (?)
6166 const TInt KMaxEraseTimeoutInSeconds = 30;
6167 iBody->SetInactivityTimeout(KMaxEraseTimeoutInSeconds);
6168 m.SetTraps(KMMCErrAll);
6169 s.FillCommandDesc( ECmdErase, 0 );
6170 SMF_INVOKES( ExecCommandSMST, EStErased )
6172 SMF_STATE(EStErased)
6173 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM9, "EStErased" );
6174 m.SetTraps( KMMCErrInitContext );
6175 iBody->RestoreInactivityTimeout();
6176 if (err != KMMCErrNone)
6178 OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT5, this, (TInt) err );
6183 SMF_STATE(EStWaitFinish)
6185 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM10, "EStWaitFinish" );
6186 s.PushCommandStack();
6187 s.FillCommandDesc(ECmdSendStatus, 0);
6188 SMF_INVOKES(ExecCommandSMST, EStWaitFinish1)
6190 SMF_STATE(EStWaitFinish1)
6192 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM11, "EStWaitFinish1" );
6193 const TMMCStatus st(s.ResponseP());
6194 s.PopCommandStack();
6197 SMF_GOTOS(EStEraseFinish);
6199 const TMMCardStateEnum st1 = st.State();
6200 if (st1 == ECardStatePrg || st1 == ECardStateRcv || st1 == ECardStateData)
6202 SMF_INVOKES(ProgramTimerSMST, EStWaitFinish);
6206 // Fall through if CURRENT_STATE is not PGM or DATA
6207 SMF_STATE(EStEraseFinish)
6209 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM12, "EStEraseFinish" );
6210 s.iState &= ~KMMCSessStateInProgress;
6211 OstTraceFunctionExitExt( DMMCSTACK_CIMERASESM_EXIT6, this, (TInt) KMMCErrBypass );
6212 return KMMCErrBypass; // to skip over the recursive entry
6217 inline TMMCErr DMMCStack::CIMReadWriteIOSM()
6219 * This macro reads/writes a stream of bytes from/to an I/O register.
6220 * This is a generalised form of FAST_IO (CMD39) MMC command.
6222 * @return MMC error code.
6233 DMMCSession& s=Session();
6234 TMMCCommandDesc& cmd = s.Command();
6235 OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEIOSM1, "Current session=0x%x; Last status=0x%x", (TUint) &s, (TUint) s.iLastStatus );
6238 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:IOSM %x",TUint(s.iLastStatus)));
6241 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEIOSM2, "EStBegin" );
6242 s.iState |= KMMCSessStateInProgress;
6243 TUint argument = (TUint(cmd.iArgument)&0x7F) << 8; // shift reg addr into a proper position
6245 switch( s.iSessionID )
6253 DMMCSocket::Panic(DMMCSocket::EMMCIOSessionID);
6256 s.FillCommandDesc( ECmdFastIO, argument );
6257 s.iBytesTransferred = ~0UL;
6259 SMF_INVOKES( AttachCardSMST, EStIOLoop ) // attachment's mandatory
6261 SMF_STATE(EStReadIO)
6263 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEIOSM3, "EStReadIO" );
6264 *(cmd.iDataMemoryP)++ = s.ResponseP()[3];
6267 SMF_BPOINT(EStIOLoop)
6269 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEIOSM4, "EStIOLoop" );
6270 s.iBytesTransferred++;
6272 if( cmd.iTotalLength == 0 )
6274 s.iState &= ~KMMCSessStateInProgress;
6278 if( s.iSessionID == ECIMWriteIO )
6280 TUint8 byte = *(cmd.iDataMemoryP)++;
6282 cmd.iArgument = (TUint(cmd.iArgument)&0xFF00) | byte;
6285 SMF_NEXTS(EStReadIO)
6287 iConfig.RemoveMode( KMMCModeEnableRetries ); // no retries on I/O registers!
6289 SMF_CALL( ExecCommandSMST )
6294 inline TMMCErr DMMCStack::CIMLockUnlockSM()
6296 * Locking and unlocking a card involves writing a data block to the card.
6297 * CIMReadWriteBlocksSM() could be used directly, but, in practive, a card must
6298 * sometimes be sent the data block twice.
6300 * @return MMC error code.
6311 DMMCSession& s=Session();
6312 TMMCCommandDesc& cmd = Command();
6313 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM1, "Current session=0x%x", &s );
6315 __KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm"));
6319 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM2, "EStBegin" );
6320 m.SetTraps(KMMCErrStatus | KMMCErrUpdPswd);
6321 cmd.iUnlockRetries = 0; // attempt counter
6322 iCMD42CmdByte = cmd.iDataMemoryP[0];
6325 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM3, "EStRetry" );
6326 __KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm:%x/%x", cmd.iUnlockRetries, (iSessionP == &iAutoUnlockSession) ? KMMCMaxAutoUnlockRetries : iConfig.iUnlockRetries));
6328 if (iCMD42CmdByte == KMMCLockUnlockErase)
6330 // Section 4.6.2 of version 4.2 of the the MMC specification states that
6331 // the maximum time for a force erase operation should be 3 minutes
6332 const TInt KMaxForceEraseTimeoutInSeconds = 3 * 60;
6333 iBody->SetInactivityTimeout(KMaxForceEraseTimeoutInSeconds);
6334 m.SetTraps(KMMCErrAll);
6338 SMF_INVOKES(CIMReadWriteBlocksSMST, EStTestR1);
6340 SMF_STATE(EStTestR1)
6341 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM4, "EStTestR1" );
6342 if (iCMD42CmdByte == KMMCLockUnlockErase)
6344 m.SetTraps(KMMCErrStatus | KMMCErrUpdPswd);
6345 iBody->RestoreInactivityTimeout();
6348 if (err & KMMCErrStatus)
6350 const TMMCStatus st = s.LastStatus(); // set in ExecCommandSM() / EStCommandIssued
6351 TMMCCommandDesc& cmd0 = Command();
6353 __KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm:EStTestR1 [err: %08x, st:%08x] : RETRY [%d]",
6354 err, (TInt)s.LastStatus(), cmd0.iUnlockRetries));
6355 OstTraceExt3( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM5, "err=%08x; Last status=%d; Unlock retries=%d", (TUint) err, (TInt) s.LastStatus(), (TUint) cmd0.iUnlockRetries );
6357 const TInt KMaxRetries = (iSessionP == &iAutoUnlockSession) ? KMMCMaxAutoUnlockRetries : iConfig.iUnlockRetries;
6359 // retry if LOCK_UNLOCK_FAIL only error bit
6360 if (!( iCMD42CmdByte == 0 // LOCK_UNLOCK = 0; SET_PWD = 0
6361 && err == KMMCErrStatus && st.Error() == KMMCStatErrLockUnlock
6362 && (iConfig.iModes & KMMCModeEnableUnlockRetry) != 0
6363 && ++cmd0.iUnlockRetries < KMaxRetries ))
6365 __KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm:abt"));
6366 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM6, "LockUnlock abort" );
6367 OstTraceFunctionExitExt( DMMCSTACK_CIMLOCKUNLOCKSM_EXIT, this, (TInt) err );
6371 __KTRACE_OPT(KPBUS1, Kern::Printf("mmc:clusm:retry"));
6372 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMLOCKUNLOCKSM7, "LockUnlock retry" );
6375 s.SynchBlock(KMMCBlockOnRetryTimer);
6376 s.iRetryTimer.OneShot(KMMCUnlockRetryGapInMilliseconds,EFalse);
6379 SMF_GOTOS(EStRetry);
6382 else if (err & KMMCErrUpdPswd)
6384 // CMD42 executed successfully, so update 'Has Password' flag
6385 if ((iCMD42CmdByte & (KMMCLockUnlockClrPwd | KMMCLockUnlockErase)) != 0)
6387 s.CardP()->iFlags&=(~KMMCardHasPassword);
6389 else if ((iCMD42CmdByte & KMMCLockUnlockSetPwd) != 0)
6391 s.CardP()->iFlags|=KMMCardHasPassword;
6396 else if (err != KMMCErrNone)
6398 OstTraceFunctionExitExt( DMMCSTACK_CIMLOCKUNLOCKSM_EXIT2, this, (TInt) err );
6406 inline TMMCErr DMMCStack::CIMAutoUnlockSM()
6408 * Performs auto-unlocking of the card stack
6410 * @return MMC error code
6417 EStInitStackAfterUnlock,
6418 EStIssuedLockUnlock,
6423 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:CIMAutoUnlockSM"));
6425 DMMCSession& s=Session();
6426 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM1, "Current session=0x%x", &s );
6430 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM2, "EStBegin" );
6431 iAutoUnlockIndex = -1;
6433 m.SetTraps(KMMCErrAll); // Trap (and ignore) all errors during auto-unlock
6435 SMF_STATE(EStNextIndex)
6437 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM3, "EStNextIndex" );
6440 iSocket->PasswordControlEnd(&Session(), err);
6443 // the cycle is finished when iAutoUnlockIndex == KMaxMultiMediaCardsPerStack
6445 if(iAutoUnlockIndex >= TInt(KMaxMMCardsPerStack))
6447 SMF_GOTOS(EStInitStackAfterUnlock);
6450 // find next available card with password in the controller store
6452 const TMapping *mp = NULL;
6454 TBool useIndex = EFalse;
6455 for (++iAutoUnlockIndex; iAutoUnlockIndex < TInt(KMaxMMCardsPerStack); ++iAutoUnlockIndex)
6457 useIndex = // card must be present with valid mapping
6458 iCardArray->CardP(iAutoUnlockIndex)->IsPresent()
6459 && (mp = iSocket->iPasswordStore->FindMappingInStore(iCardArray->CardP(iAutoUnlockIndex)->CID())) != NULL
6460 && mp->iState == TMapping::EStValid;
6462 // don't increment iAutoUnlockIndex in continuation loop
6469 // if no usable index, complete with no error code
6470 SMF_GOTOS(EStInitStackAfterUnlock);
6474 // We've found a locked card with a password in the password store,
6475 // so attempt to unlock using the CIMLockUnlockSMST state machine.
6477 // Upon completion, test the next card before performing further initialisation.
6480 TMMCard &cd = *(iCardArray->CardP(iAutoUnlockIndex++));
6481 OstTrace1( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM4, "Attempting to unlock card %d", cd.Number() );
6485 const TInt kPWD_LEN = mp->iPWD.Length();
6486 iPSLBuf[0] = 0; // LOCK_UNLOCK = 0; unlock
6487 iPSLBuf[1] = static_cast<TUint8>(kPWD_LEN);
6488 TPtr8 pwd(&iPSLBuf[2], kPWD_LEN);
6491 const TInt kBlockLen = 1 + 1 + kPWD_LEN;
6493 s.FillCommandDesc(ECmdLockUnlock);
6494 s.FillCommandArgs(0, kBlockLen, iPSLBuf, kBlockLen);
6496 SMF_INVOKES( CIMLockUnlockSMST, EStNextIndex )
6498 SMF_STATE(EStInitStackAfterUnlock)
6500 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM5, "EStInitStackAfterUnlock" );
6502 // We've attempted to unlock all cards (successfully or not)
6503 // - Now perform second-stage initialisation that can only be performed
6504 // on unlocked cards (such as setting bus width, high speed etc..)
6509 SMF_INVOKES( InitStackAfterUnlockSMST, EStDone )
6512 OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMAUTOUNLOCKSM6, "EStDone" );
6517 inline TMMCErr DMMCStack::NoSessionSM()
6519 * A null state machine function. Just returns KMMCErrNotSupported.
6521 * @return KMMCErrNotSupported
6532 return( KMMCErrNotSupported );
6538 // Static adapter functions to top-level state machines.
6541 TMMCErr DMMCStack::NakedSessionSMST(TAny* aStackP) // ECIMNakedSession
6542 { return( static_cast<DMMCStack *>(aStackP)->NakedSessionSM() ); }
6544 TMMCErr DMMCStack::CIMUpdateAcqSMST( TAny* aStackP ) // ECIMUpdateAcq
6545 { return( static_cast<DMMCStack *>(aStackP)->CIMUpdateAcqSM() ); }
6547 TMMCErr DMMCStack::CIMInitStackSMST( TAny* aStackP ) // ECIMInitStack
6548 { return( static_cast<DMMCStack *>(aStackP)->CIMInitStackSM() ); }
6550 TMMCErr DMMCStack::CIMCheckStackSMST( TAny* aStackP ) // ECIMCheckStack
6551 { return( static_cast<DMMCStack *>(aStackP)->CIMCheckStackSM() ); }
6553 TMMCErr DMMCStack::CIMSetupCardSMST(TAny* aStackP) // ECIMSetupCard
6554 { return( static_cast<DMMCStack *>(aStackP)->CIMSetupCardSM() ); }
6556 EXPORT_C TMMCErr DMMCStack::CIMReadWriteBlocksSMST(TAny* aStackP) // ECIMReadBlock, ECIMWriteBlock, ECIMReadMBlock, ECIMWriteMBlock
6557 { return( static_cast<DMMCStack *>(aStackP)->CIMReadWriteBlocksSM() ); }
6559 TMMCErr DMMCStack::CIMEraseSMST(TAny* aStackP) // ECIMEraseSector, ECIMEraseGroup
6560 { return( static_cast<DMMCStack *>(aStackP)->CIMEraseSM() ); }
6562 TMMCErr DMMCStack::CIMReadWriteIOSMST(TAny* aStackP) // ECIMReadIO, ECIMWriteIO
6563 { return( static_cast<DMMCStack *>(aStackP)->CIMReadWriteIOSM() ); }
6565 TMMCErr DMMCStack::CIMLockUnlockSMST(TAny* aStackP) // ECIMLockUnlock
6566 { return( static_cast<DMMCStack *>(aStackP)->CIMLockUnlockSM() ); }
6568 TMMCErr DMMCStack::NoSessionSMST(TAny* aStackP) // ECIMLockStack
6569 { return( static_cast<DMMCStack *>(aStackP)->NoSessionSM() ); }
6571 TMMCErr DMMCStack::InitStackAfterUnlockSMST( TAny* aStackP )
6572 { return( static_cast<DMMCStack *>(aStackP)->InitStackAfterUnlockSM() ); }
6574 TMMCErr DMMCStack::AcquireStackSMST( TAny* aStackP )
6575 { return( static_cast<DMMCStack *>(aStackP)->AcquireStackSM() ); }
6577 TMMCErr DMMCStack::CheckStackSMST( TAny* aStackP )
6578 { return( static_cast<DMMCStack *>(aStackP)->CheckStackSM() ); }
6580 TMMCErr DMMCStack::ModifyCardCapabilitySMST( TAny* aStackP )
6581 { return( static_cast<DMMCStack *>(aStackP)->ModifyCardCapabilitySM() ); }
6583 TMMCErr DMMCStack::AttachCardSMST( TAny* aStackP )
6584 { return( static_cast<DMMCStack *>(aStackP)->AttachCardSM() ); }
6586 TMMCErr DMMCStack::ExecCommandSMST( TAny* aStackP )
6587 { return( static_cast<DMMCStack *>(aStackP)->ExecCommandSM() ); }
6589 TMMCErr DMMCStack::IssueCommandCheckResponseSMST(TAny* aStackP)
6590 { return( static_cast<DMMCStack *>(aStackP)->IssueCommandCheckResponseSM() ); }
6592 TMMCErr DMMCStack::PollGapTimerSMST( TAny* aStackP )
6593 { return( static_cast<DMMCStack *>(aStackP)->PollGapTimerSM() ); }
6595 TMMCErr DMMCStack::RetryGapTimerSMST( TAny* aStackP )
6596 { return( static_cast<DMMCStack *>(aStackP)->RetryGapTimerSM() ); }
6598 TMMCErr DMMCStack::ProgramTimerSMST(TAny *aStackP)
6599 { return static_cast<DMMCStack *>(aStackP)->ProgramTimerSM(); }
6601 TMMCErr DMMCStack::GoIdleSMST( TAny* aStackP )
6602 { return( static_cast<DMMCStack *>(aStackP)->GoIdleSM() ); }
6604 TMMCErr DMMCStack::CheckLockStatusSMST( TAny* aStackP )
6605 { return( static_cast<DMMCStack *>(aStackP)->CheckLockStatusSM() ); }
6607 TMMCErr DMMCStack::CIMAutoUnlockSMST( TAny* aStackP )
6608 { return( static_cast<DMMCStack *>(aStackP)->CIMAutoUnlockSM() ); }
6610 TMMCErr DMMCStack::ExecSleepCommandSMST( TAny* aStackP )
6611 { return( static_cast<DMMCStack *>(aStackP)->ExecSleepCommandSM() ); }
6613 TMMCErr DMMCStack::ExecAwakeCommandSMST( TAny* aStackP )
6614 { return( static_cast<DMMCStack *>(aStackP)->ExecAwakeCommandSM() ); }
6616 // Static interfaces to ASSP layer SM functions
6618 TMMCErr DMMCStack::DoPowerUpSMST( TAny* aStackP )
6619 { return( static_cast<DMMCStack *>(aStackP)->DoPowerUpSM() ); }
6621 TMMCErr DMMCStack::InitClockOnSMST( TAny* aStackP )
6622 { return( static_cast<DMMCStack *>(aStackP)->InitClockOnSM() ); }
6624 EXPORT_C TMMCErr DMMCStack::IssueMMCCommandSMST( TAny* aStackP )
6625 { return( static_cast<DMMCStack *>(aStackP)->IssueMMCCommandSM() ); }
6627 TMMCErr DMMCStack::DetermineBusWidthAndClockSMST( TAny* aStackP )
6628 { return( static_cast<DMMCStack *>(aStackP)->DetermineBusWidthAndClockSM() ); }
6630 TMMCErr DMMCStack::ConfigureHighSpeedSMST( TAny* aStackP )
6631 { return( static_cast<DMMCStack *>(aStackP)->ConfigureHighSpeedSM() ); }
6633 TMMCErr DMMCStack::ExecSwitchCommandST( TAny* aStackP )
6634 { return( static_cast<DMMCStack *>(aStackP)->ExecSwitchCommand() ); }
6636 TMMCErr DMMCStack::SwitchToLowVoltageSMST( TAny* aStackP )
6637 { return( static_cast<DMMCStack *>(aStackP)->SwitchToLowVoltageSM() ); }
6639 TMMCErr DMMCStack::LowVoltagePowerupTimerSMST(TAny *aStackP)
6640 { return static_cast<DMMCStack *>(aStackP)->LowVoltagePowerupTimerSM(); }
6642 TMMCErr DMMCStack::ExecBusTestSMST( TAny* aStackP )
6643 { return( static_cast<DMMCStack *>(aStackP)->ExecBusTestSM() ); }
6645 TMMCErr DMMCStack::DoWakeUpSMST( TAny* aStackP )
6647 MDoWakeUp* dowakeup = NULL;
6648 static_cast<DMMCStack *>(aStackP)->GetInterface(KInterfaceDoWakeUpSM, (MInterface*&) dowakeup);
6651 return dowakeup->DoWakeUpSM();
6655 // Interface not supported at PSL Level
6656 return KMMCErrNotSupported;
6661 EXPORT_C DMMCSession* DMMCStack::AllocSession(const TMMCCallBack& aCallBack) const
6663 * Factory function to create DMMCSession derived object. Non-generic MMC
6664 * controllers can override this to generate more specific objects.
6665 * @param aCallBack Callback function to notify the client that a session has completed
6666 * @return A pointer to the new session
6669 OstTraceFunctionEntry1( DMMCSTACK_ALLOCSESSION_ENTRY, this );
6670 return new DMMCSession(aCallBack);
6673 EXPORT_C void DMMCStack::Dummy1() {}
6676 * Calls the PSL-implemented function SetBusWidth() if the bus width has changed
6679 void DMMCStack::DoSetBusWidth(TUint32 aBusWidth)
6681 OstTraceFunctionEntryExt( DMMCSTACK_DOSETBUSWIDTH_ENTRY, this );
6682 if (iBody->iCurrentSelectedBusWidth != aBusWidth)
6684 iBody->iCurrentSelectedBusWidth = aBusWidth;
6685 SetBusWidth(aBusWidth);
6687 OstTraceFunctionExit1( DMMCSTACK_DOSETBUSWIDTH_EXIT, this );
6691 * Sets iConfig.iBusConfig.iBusClock - which the PSL SHOULD use to set the clock before every command.
6693 * Some PSLs, however, may only change the clock when SetBusConfigDefaults() is called,
6694 * so if the clock has changed, SetBusConfigDefaults() is called
6696 * @param aClock The requested clock frequency in Kilohertz
6698 void DMMCStack::DoSetClock(TUint32 aClock)
6700 OstTraceFunctionEntryExt( DMMCSTACK_DOSETCLOCK_ENTRY, this );
6701 iConfig.iBusConfig.iBusClock = aClock;
6703 if (iPoweredUp&&(iBody->iCurrentSelectedClock != aClock))
6705 iBody->iCurrentSelectedClock = aClock;
6706 SetBusConfigDefaults(iConfig.iBusConfig, aClock);
6708 OstTraceFunctionExit1( DMMCSTACK_DOSETCLOCK_EXIT, this );
6712 TUint DMMCStack::MaxTranSpeedInKilohertz(const TMMCard& aCard) const
6714 OstTraceFunctionEntry1( DMMCSTACK_MAXTRANSPEEDINKILOHERTZ_ENTRY, this );
6715 TUint32 highSpeedClock = aCard.HighSpeedClock();
6716 TUint ret = highSpeedClock ? highSpeedClock : aCard.MaxTranSpeedInKilohertz();
6717 OstTraceFunctionExitExt( DMMCSTACK_MAXTRANSPEEDINKILOHERTZ_EXIT, this, ret );
6723 EXPORT_C void DMMCStack::SetBusWidth(TUint32 /*aBusWidth*/)
6727 EXPORT_C void DMMCStack::MachineInfo(TDes8& /*aMachineInfo*/)
6731 TBusWidth DMMCStack::BusWidthEncoding(TInt aBusWidth) const
6733 * Returns the bus width as a TBusWidth given a card's bus width
6734 * expressed as an integer (1,4 or 8)
6735 * @return the bus width encoded as a TBusWidth
6738 OstTraceFunctionEntryExt( DMMCSTACK_BUSWIDTHENCODING_ENTRY, this );
6739 TBusWidth busWidth = EBusWidth1;
6744 busWidth = EBusWidth8;
6747 busWidth = EBusWidth4;
6751 busWidth = EBusWidth1;
6754 DMMCSocket::Panic(DMMCSocket::EMMCBadBusWidth);
6757 OstTraceFunctionExitExt( DMMCSTACK_BUSWIDTHENCODING_EXIT, this, ( TUint )&( busWidth ) );
6764 EXPORT_C DMMCSocket::DMMCSocket(TInt aSocketNumber, TMMCPasswordStore* aPasswordStore)
6766 * Constructs a DMMCSocket class
6767 * @param aSocketNumber the socket ID
6768 * @param aPasswordStore pointer to the password store
6770 :DPBusSocket(aSocketNumber),
6771 iPasswordStore(aPasswordStore)
6773 OstTraceFunctionEntryExt( DMMCSOCKET_DMMCSOCKET_ENTRY, this );
6776 TInt DMMCSocket::TotalSupportedCards()
6778 * Returns the total number of MMC slots supported by the socket.
6779 * @return The number of MMC slots supported by the socket
6782 OstTraceFunctionEntry1( DMMCSOCKET_TOTALSUPPORTEDCARDS_ENTRY, this );
6783 OstTraceFunctionExitExt( DMMCSOCKET_TOTALSUPPORTEDCARDS_EXIT, this, iMachineInfo.iTotalSockets );
6784 return iMachineInfo.iTotalSockets;
6788 // -------- Password store management --------
6791 // The persistent file is a contiguous sequence of entries.
6792 // An entry format is [CID@16 | PWD_LEN@4 | PWD@PWD_LEN].
6793 // CID and PWD_LEN are both stored in big endian format.
6796 TInt DMMCSocket::PrepareStore(TInt aBus, TInt aFunc, TLocalDrivePasswordData &aData)
6798 * Called from media driver before CMD42 session engaged, in kernel server context
6799 * so that mappings can be allocated or deallocated.
6801 * Using zero-length passwords for MMC operations is disallowed by this function.
6802 * Locking with and clearing a null password is failed with KErrAccessDenied.
6803 * If the drive is already mounted, then TBusLocalDrive::Unlock() will fail with
6804 * KErrAlreadyExists. Otherwise, this function will fail with KErrLocked, which
6805 * is translated to KErrAccessDenied in Unlock(), in the same way as unlocking
6806 * a locked card with the wrong password
6808 * @param aBus The card to be unlocked.
6809 * @param aFunc The operation to perform (EPasswordLock, EPasswordUnlock, EPasswordClear).
6810 * @param aData TLocalDrivePasswordData reference containing the password
6811 * @return KErrAccessDenied An attempt to lock or clear was made with a NULL password.
6812 * @return KErrLocked An an attempt to unlock was made with a NULL password.
6813 * @return KErrNone on success
6816 OstTraceExt3(TRACE_FLOW, DMMCSOCKET_PREPARESTORE_ENTRY, "DMMCSocket::PrepareStore;aBus=%d;aFunc=%d;this=%x", aBus, aFunc, (TUint) this);
6819 TMMCard *card=iStack->CardP(aBus);
6820 __ASSERT_ALWAYS(card, Panic(EMMCSessionNoPswdCard));
6821 const TCID &cid = card->CID();
6825 case DLocalDrive::EPasswordLock:
6827 TMediaPassword newPwd = *aData.iNewPasswd;
6829 if (newPwd.Length() == 0)
6830 r = KErrAccessDenied;
6832 r = PasswordControlStart(cid, aData.iStorePasswd ? &newPwd : NULL);
6836 case DLocalDrive::EPasswordUnlock:
6838 TMediaPassword curPwd = *aData.iOldPasswd;
6840 if (curPwd.Length() == 0)
6843 r = PasswordControlStart(cid, aData.iStorePasswd ? &curPwd : NULL);
6847 case DLocalDrive::EPasswordClear:
6849 TMediaPassword curPwd = *aData.iOldPasswd;
6851 if (curPwd.Length() == 0)
6852 r = KErrAccessDenied;
6854 r = PasswordControlStart(cid, aData.iStorePasswd ? &curPwd : NULL);
6859 Panic(EMMCSessionPswdCmd);
6863 OstTraceFunctionExitExt( DMMCSOCKET_PREPARESTORE_EXIT, this, r );
6868 TInt DMMCSocket::PasswordControlStart(const TCID &aCID, const TMediaPassword *aPWD)
6870 * Remove any non-validated mappings from the store, and allocate a binding for
6871 * the card's CID if necessary.
6873 * s = source (current) password stored; t = target (new) password should be stored
6876 * t is equivalent to iMPTgt.Length() > 0, which is used by PasswordControlEnd().
6878 * The target password is not stored in the store at this point, but in the stack.
6879 * This leaves any existing mapping which can be used for recovery if the operation
6880 * fails. This means the user does not have to re-enter the right password after
6881 * trying to unlock a card with the wrong password.
6883 * See PasswordControlEnd() for recovery policy.
6886 OstTraceFunctionEntry1( DMMCSOCKET_PASSWORDCONTROLSTART_ENTRY, this );
6887 TInt r = KErrNone; // error code
6889 TBool changed = EFalse; // compress store if changed
6891 TBuf8<KMMCCIDLength> cid; // convert to TBuf8<> for comparison
6892 cid.SetLength(KMMCCIDLength);
6895 TBool s = EFalse; // source password (current mapping)
6896 TBool t = aPWD != NULL; // target pasword (new value for mapping)
6898 // remove any bindings which were not validated. This is all non EStValid
6899 // bindings - the previous operation could have failed before CMD42 was sent,
6900 // in which case its state would be EStPending, not EStInvalid.
6902 // an inefficiency exists where an invalid binding for the target CID exists.
6903 // This could be reused instead of being deallocated and reallocated. This
6904 // situation would occur if the user inserted a card whose password was not
6905 // known to the machine, unlocked it with the wrong password and tried again.
6906 // The case is rare and the cost is run-time speed, which is not noticeable,
6907 // The run-time memory usage is equivalent, so it is probably not worth the
6908 // extra rom bytes and logic.
6910 for (TInt i = 0; i < iPasswordStore->iStore->Count(); )
6912 if ((*iPasswordStore->iStore)[i].iState != TMapping::EStValid)
6914 iPasswordStore->iStore->Remove(i); // i becomes index for next item
6919 if ((*iPasswordStore->iStore)[i].iCID == cid)
6926 iStack->iMPTgt.Zero();
6929 iStack->iMPTgt = *aPWD;
6933 TMediaPassword mp; // empty, to indicate !s
6934 if ((r = iPasswordStore->InsertMapping(aCID, mp, TMapping::EStPending)) != KErrNone)
6936 OstTraceFunctionExitExt( DMMCSOCKET_PASSWORDCONTROLSTART_EXIT1, this, r );
6945 iPasswordStore->iStore->Compress();
6947 OstTraceFunctionExitExt( DMMCSOCKET_PASSWORDCONTROLSTART_EXIT2, this, r );
6953 void DMMCSocket::PasswordControlEnd(DMMCSession *aSessP, TInt aResult)
6955 * called by DMMCStack::SchedCompletionPass() after CMD42 has completed to
6956 * update internal store. This function does not run in ks context and so
6957 * can only invalidate bindings for later removal in PasswordControlStart().
6959 * s = source (current) password stored; t = target (new) password should be stored
6962 * If the operation fails, then a recovery policy is used so the user does
6963 * not lose the good current binding and have to re-enter the password.
6971 * N nothing V validate W wipe
6972 * I invalidate R restore
6974 * See PasswordControlStart() for details of how store set up.
6977 OstTraceFunctionEntryExt( DMMCSOCKET_PASSWORDCONTROLEND_ENTRY, this );
6978 // autounlock is a special case because the PasswordControlStart() will
6979 // not have been called (the CID is not known in ks context.) The mapping
6980 // for this specific card is removed on failure, because it is the current
6981 // mapping that is definitely wrong.
6983 TBuf8<KMMCCIDLength> cid; // convert to TBuf8<> for comparison
6984 cid.SetLength(KMMCCIDLength);
6985 aSessP->CardP()->CID().Copy(&cid[0]);
6987 if (aSessP == &iStack->iAutoUnlockSession)
6989 TBool changed = EFalse; // compress store if changed
6991 for (TInt j = 0; j < iPasswordStore->iStore->Count(); )
6993 TMapping &mp = (*iPasswordStore->iStore)[j];
6996 mp.iState = (aResult == KErrNone ? TMapping::EStValid : TMapping::EStInvalid);
6997 if(mp.iState == TMapping::EStInvalid)
6999 iPasswordStore->iStore->Remove(j);
7014 iPasswordStore->iStore->Compress();
7018 const TMediaPassword &mpTgt = iStack->iMPTgt;
7019 TBool s = EFalse; // default value in case no mapping
7020 TBool t = mpTgt.Length() > 0;
7021 TBool f = (aResult != KErrNone);
7023 TMapping mp, *pmp; // get mapping to mutate
7025 TInt psn = iPasswordStore->iStore->Find(mp, iPasswordStore->iIdentityRelation);
7026 if (psn == KErrNotFound)
7028 OstTraceFunctionExit1( DMMCSOCKET_PASSWORDCONTROLEND_EXIT1, this );
7033 pmp = &(*iPasswordStore->iStore)[psn];
7034 s = pmp->iPWD.Length() > 0;
7040 pmp->iState = TMapping::EStValid; // restore
7043 if (t) // ~s & t & f
7044 pmp->iState = TMapping::EStInvalid; // invalidate
7051 pmp->iState = TMapping::EStValid; // validate
7056 if (s) // s & ~t & ~f
7057 pmp->iState = TMapping::EStInvalid; // wipe
7060 } // else if (aSessP == &iStack->iAutoUnlockSession)
7061 OstTraceFunctionExit1( DMMCSOCKET_PASSWORDCONTROLEND_EXIT2, this );
7065 TMMCPasswordStore::TMMCPasswordStore()
7069 : iIdentityRelation(TMMCPasswordStore::CompareCID)
7071 OstTraceFunctionEntry1( TMMCPASSWORDSTORE_TMMCPASSWORDSTORE_ENTRY, this );
7074 TInt TMMCPasswordStore::Init()
7076 * Initialises the password store and allocates resources.
7077 * @return KErrNone if successful, standard error code otherwise.
7080 OstTraceFunctionEntry1( TMMCPASSWORDSTORE_INIT_ENTRY, this );
7081 // We don't have a destructor yet as this object lasts forever
7082 iStore = new RArray<TMapping>(4, _FOFF(TMapping, iCID));
7085 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_INIT_EXIT1, this, KErrNoMemory );
7086 return KErrNoMemory;
7088 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_INIT_EXIT2, this, KErrNone );
7092 EXPORT_C TBool TMMCPasswordStore::IsMappingIncorrect(const TCID& aCID, const TMediaPassword& aPWD)
7094 * Returns true if the password is definitely incorrect, i.e. if a valid entry with a
7095 * different password exists. Returns false if correct (because the mapping matches,)
7096 * or if cannot tell (because no valid mapping.)
7099 OstTraceFunctionEntry1( TMMCPASSWORDSTORE_ISMAPPINGINCORRECT_ENTRY, this );
7100 TMapping* pmp = FindMappingInStore(aCID);
7101 TBool ret = pmp != 0 && pmp->iState == TMapping::EStValid && pmp->iPWD.Compare(aPWD) != 0;
7102 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_ISMAPPINGINCORRECT_EXIT, this, ret );
7106 TMapping *TMMCPasswordStore::FindMappingInStore(const TCID &aCID)
7108 * return pointer to aCID mapping in store or NULL if not found
7111 OstTraceFunctionEntry1( TMMCPASSWORDSTORE_FINDMAPPINGINSTORE_ENTRY, this );
7112 TMapping *pmp = NULL;
7113 TMapping mp; // 8 + 16 + 8 + 16 + 4 bytes
7114 mp.iCID.SetLength(KMMCCIDLength);
7115 aCID.Copy(&mp.iCID[0]);
7117 TInt psn=iStore->Find(mp, iIdentityRelation);
7118 if(psn!=KErrNotFound)
7120 pmp = &(*iStore)[psn];
7122 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_FINDMAPPINGINSTORE_EXIT, this, ( TUint )( pmp ) );
7126 TInt TMMCPasswordStore::InsertMapping(const TCID &aCID, const TMediaPassword &aPWD, TMapping::TState aState)
7128 * Ensures that a mapping from aCID to aPWD exists in the store. If an
7129 * existing entry does not exist to mutate, then insert a new one. This
7130 * may cause an allocation, depending on the granularity and count.
7132 * If the CID is already bound to something in the store, then this operation
7133 * is a binary search, otherwise it may involve kernel heap allocation.
7136 OstTraceFunctionEntry1( TMMCPASSWORDSTORE_INSERTMAPPING_ENTRY, this );
7139 mpN.iCID.SetLength(KMMCCIDLength);
7140 aCID.Copy(&mpN.iCID[0]); // copies from aCID into buffer.
7142 TInt psn = iStore->Find(mpN, iIdentityRelation);
7143 if(psn == KErrNotFound)
7145 mpN.iPWD.Copy(aPWD);
7146 mpN.iState = aState;
7147 r=iStore->Insert(mpN, iStore->Count());
7151 TMapping &mpE = (*iStore)[psn];
7152 mpE.iPWD.Copy(aPWD);
7153 mpE.iState = aState;
7157 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_INSERTMAPPING_EXIT, this, r );
7161 TInt TMMCPasswordStore::PasswordStoreLengthInBytes()
7163 * virtual from DPeriphBusController, kern exec
7164 * return number of bytes needed for persistent file representation
7165 * of the password store
7168 OstTraceFunctionEntry1( TMMCPASSWORDSTORE_PASSWORDSTORELENGTHINBYTES_ENTRY, this );
7171 for (TInt i = 0; i < iStore->Count(); ++i)
7173 const TMapping &mp = (*iStore)[i];
7174 if (mp.iState == TMapping::EStValid)
7175 sz += KMMCCIDLength + sizeof(TInt32) + mp.iPWD.Length();
7178 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_PASSWORDSTORELENGTHINBYTES_EXIT, this, sz );
7182 TBool TMMCPasswordStore::ReadPasswordData(TDes8 &aBuf)
7184 * virtual from DPeriphBusController, kern exec
7185 * fills descriptor with persistent representation of password store
7186 * data. aBuf is resized to contain exactly the password data from
7187 * the store. If its maximum length is not enough then KErrOverflow
7188 * is returned and aBuf is not mutated.
7191 OstTraceFunctionEntry1( TMMCPASSWORDSTORE_READPASSWORDDATA_ENTRY, this );
7192 TInt r=KErrNone; // error code
7194 if (PasswordStoreLengthInBytes() > aBuf.MaxLength())
7199 for (TInt i = 0; i < iStore->Count(); ++i)
7201 const TMapping &mp = (*iStore)[i];
7203 if (mp.iState == TMapping::EStValid)
7205 aBuf.Append(mp.iCID);
7207 TUint8 lenBuf[sizeof(TInt32)]; // length, big-endian
7208 TMMC::BigEndian4Bytes(lenBuf, TInt32(mp.iPWD.Length()));
7209 aBuf.Append(&lenBuf[0], sizeof(TInt32));
7211 aBuf.Append(mp.iPWD);
7218 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_READPASSWORDDATA_EXIT, this, r );
7223 TInt TMMCPasswordStore::WritePasswordData(TDesC8 &aBuf)
7225 * virtual from DPeriphBusController, kern server
7226 * replace current store with data from persistent representation in aBuf.
7229 OstTraceFunctionEntry1( TMMCPASSWORDSTORE_WRITEPASSWORDDATA_ENTRY, this );
7230 // should only be called at boot up, but remove chance of duplicate entries
7233 TInt iBIdx; // buffer index
7235 // check buffer integrity
7237 TBool corrupt = EFalse; // abort flag
7238 for (iBIdx = 0; iBIdx < aBuf.Length(); )
7240 // enough raw data for CID, PWD_LEN and 1 byte of PWD
7241 corrupt = TUint(aBuf.Length() - iBIdx) < KMMCCIDLength + sizeof(TUint32) + 1;
7245 // PWD_LEN is valid and enough raw data left for PWD
7246 iBIdx += KMMCCIDLength;
7247 const TInt32 pwd_len(TMMC::BigEndian32(&aBuf[iBIdx]));
7249 (pwd_len <= TInt32(KMaxMediaPassword))
7250 && aBuf.Length() - iBIdx >= TInt(sizeof(TUint32)) + pwd_len );
7254 // skip over PWD_LEN and PWD to next entry
7255 iBIdx += sizeof(TInt32) + pwd_len;
7260 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_WRITEPASSWORDDATA_EXIT1, this, KErrCorrupt );
7264 // Build the store from the entries in the buffer.
7265 TInt r = KErrNone; // error code
7266 for (iBIdx = 0; r == KErrNone && iBIdx < aBuf.Length(); )
7268 TPtrC8 pCID(&aBuf[iBIdx], KMMCCIDLength); // CID
7269 const TCID cid(pCID.Ptr());
7271 const TInt32 pwd_len(TMMC::BigEndian32(&aBuf[iBIdx + KMMCCIDLength]));
7273 pwd.Copy(&aBuf[iBIdx + KMMCCIDLength + sizeof(TInt32)], pwd_len);
7275 iBIdx += KMMCCIDLength + sizeof(TInt32) + pwd_len;
7276 r = InsertMapping(cid, pwd, TMapping::EStValid);
7279 // it may be acceptable to use a partially created store, providing the
7280 // sections that do exist are valid. Alternatively, the operation should
7281 // atomic from the startup thread's point of view.
7286 OstTraceFunctionExitExt( TMMCPASSWORDSTORE_WRITEPASSWORDDATA_EXIT2, this, r );
7290 TInt TMMCPasswordStore::CompareCID(const TMapping& aLeft, const TMapping& aRight)
7292 * CID Comparason Functions for RArray::Find
7295 OstTraceFunctionEntry0( TMMCPASSWORDSTORE_COMPARECID_ENTRY );
7296 return(aLeft.iCID == aRight.iCID);
7299 void DMMCSocket::InitiatePowerUpSequence()
7301 * Initiates a power up sequence on the stack
7304 OstTraceFunctionEntry1( DMMCSOCKET_INITIATEPOWERUPSEQUENCE_ENTRY, this );
7305 iStack->PowerUpStack();
7306 OstTraceFunctionExit1( DMMCSOCKET_INITIATEPOWERUPSEQUENCE_EXIT, this );
7309 TBool DMMCSocket::CardIsPresent()
7311 * Indicates the presence of a card.
7312 * @return ETrue if a card is present, EFalse otherwise
7315 OstTraceFunctionEntry1( DMMCSOCKET_CARDISPRESENT_ENTRY, this );
7316 TInt r = iStack->HasCardsPresent();
7317 OstTraceFunctionExitExt( DMMCSOCKET_CARDISPRESENT_EXIT, this, r );
7321 void DMMCSocket::AdjustPartialRead(const TMMCard* aCard, TUint32 aStart, TUint32 aEnd, TUint32* aPhysStart, TUint32* aPhysEnd) const
7323 * Calculates the minimum range that must be read off a card, an optimisation that takes advantage
7324 * of the partial read feature found on some cards. It takes the logical range that the media driver
7325 * wants to read from the card, and increases it to take into account factors such as FIFO width and
7326 * minimum DMA transfer size.
7327 * @param aCard A pointer to the MMC Card
7328 * @param aStart The required start position
7329 * @param aEnd The required end position
7330 * @param aPhysStart The adjusted start position
7331 * @param aPhysEnd The adjusted end position
7334 OstTraceFunctionEntryExt( DMMCSOCKET_ADJUSTPARTIALREAD_ENTRY, this );
7335 iStack->AdjustPartialRead(aCard, aStart, aEnd, aPhysStart, aPhysEnd);
7336 OstTraceFunctionExit1( DMMCSOCKET_ADJUSTPARTIALREAD_EXIT, this );
7339 void DMMCSocket::GetBufferInfo(TUint8** aMDBuf, TInt* aMDBufLen)
7341 * Returns the details of the buffer allocated by the socket for data transfer operations. The buffer
7342 * is allocated and configured at the variant layer to allow , for example, contiguous pages to be
7343 * allocated for DMA transfers.
7344 * @param aMDBuf A pointer to the allocated buffer
7345 * @param aMDBufLen The length of the allocated buffer
7348 OstTraceFunctionEntryExt( DMMCSOCKET_GETBUFFERINFO_ENTRY, this );
7349 iStack->GetBufferInfo(aMDBuf, aMDBufLen);
7350 OstTraceFunctionExit1( DMMCSOCKET_GETBUFFERINFO_EXIT, this );
7353 void DMMCSocket::Reset1()
7355 * Resets the socket by powering down the stack.
7356 * If there are operations in progress (inCritical), this call will be deferred
7357 * until the operation is complete. In the case of an emergency power down,
7358 * this will occur immediately.
7361 OstTraceFunctionEntry1( DMMCSOCKET_RESET1_ENTRY, this );
7362 if (iState == EPBusCardAbsent)
7364 // Reset is result of card eject!
7365 iStack->iStackState |= KMMCStackStateCardRemoved;
7369 iStack->PowerDownStack();
7370 OstTraceFunctionExit1( DMMCSOCKET_RESET1_EXIT, this );
7373 void DMMCSocket::Reset2()
7375 * Resets the socket in response to a PSU fault or media change.
7376 * Called after Reset1, gives the opportunity to free upp allocated resources
7379 // No need to do anything here, as the only thing to do is power down the
7380 // stack, which is performed in ::Reset1
7383 TInt DMMCSocket::Init()
7385 * Allocates resources and initialises the MMC socket and associated stack object.
7386 * @return KErrNotReady if no stack has been allocated, standard error code otherwise
7389 OstTraceFunctionEntry1( DMMCSOCKET_INIT_ENTRY, this );
7390 __KTRACE_OPT(KPBUS1,Kern::Printf(">MMC:Init"));
7394 // We need to make sure the stack is initialised,
7395 // as DPBusSocket::Init() will initiate a power up sequence
7398 OstTraceFunctionExitExt( DMMCSOCKET_INIT_EXIT1, this, KErrNotReady );
7399 return KErrNotReady;
7402 TInt r = iStack->Init();
7405 OstTraceFunctionExitExt( DMMCSOCKET_INIT_EXIT2, this, r );
7409 r = DPBusSocket::Init();
7412 OstTraceFunctionExitExt( DMMCSOCKET_INIT_EXIT3, this, r );
7416 OstTraceFunctionExitExt( DMMCSOCKET_INIT_EXIT4, this, KErrNone );
7420 void DMMCSocket::GetMachineInfo()
7422 * Gets the platform specific configuration information.
7423 * @see TMMCMachineInfo
7426 OstTraceFunctionEntry1( DMMCSOCKET_GETMACHINEINFO_ENTRY, this );
7427 // Get machine info from the stack
7428 iStack->MachineInfo(iMachineInfo);
7430 __KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iTotalSockets %u", iMachineInfo.iTotalSockets));
7431 __KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iTotalMediaChanges %u", iMachineInfo.iTotalMediaChanges));
7432 __KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iTotalPrimarySupplies %u", iMachineInfo.iTotalPrimarySupplies));
7433 __KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iSPIMode %u", iMachineInfo.iSPIMode));
7434 __KTRACE_OPT(KPBUS1, Kern::Printf(">GetMI : iBaseBusNumber %u", iMachineInfo.iBaseBusNumber));
7435 OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSOCKET_GETMACHINEINFO, "iTotalSockets=%d; iTotalMediaChanges=%d; iTotalPrimarySupplies=%d; iSPIMode=%d; iBaseBusNumber=%d", iMachineInfo.iTotalSockets, iMachineInfo.iTotalMediaChanges, iMachineInfo.iTotalPrimarySupplies, iMachineInfo.iSPIMode, iMachineInfo.iBaseBusNumber );
7438 OstTraceFunctionExit1( DMMCSOCKET_GETMACHINEINFO_EXIT, this );
7442 // MMC specific functions
7444 EXPORT_C void DMMCSocket::Panic(TMMCPanic aPanic)
7446 * Panic the MMC Controller
7447 * @param aPanic The panic code
7450 OstTraceFunctionEntry0( DMMCSOCKET_PANIC_ENTRY );
7451 _LIT(KPncNm,"PBUS-MMC");
7452 Kern::PanicCurrentThread(KPncNm,aPanic);
7455 EXPORT_C DMMCPsu::DMMCPsu(TInt aPsuNum, TInt aMediaChangedNum)
7457 * Constructor for a DMMCPsu object
7458 * @param aPsuNum The power supply number
7459 * @param aMediaChangedNum The associated media change number
7461 : DPBusPsuBase(aPsuNum, aMediaChangedNum)
7463 OstTraceFunctionEntryExt( DMMCPSU_DMMCPSU_ENTRY, this );
7465 iVoltageSetting=0x00ffc000; // Default voltage range - 2.6V to 3.6V (OCR reg. format).
7466 OstTraceFunctionExit1( DMMCPSU_DMMCPSU_EXIT, this );
7469 EXPORT_C TInt DMMCPsu::DoCreate()
7471 * Create a DMMCPsu object.
7472 * This should be overridden at the variant layer to allow interrupts and
7473 * other variant-specific parameters to be initialised. The default
7474 * implementation does nothing.
7475 * @return Standard Symbian OS error code.
7482 void DMMCPsu::SleepCheck(TAny* aPtr)
7484 * Checks if media can be placed in Sleep state
7485 * and therefore if VccQ supply can be turned off.
7487 * @Param aPtr reference to DMMCPsu Object to be acted upon.
7490 OstTraceFunctionEntry0( DMMCPSU_SLEEPCHECK_ENTRY );
7491 DMMCPsu& self = *static_cast<DMMCPsu*>(aPtr);
7494 (self.iNotLockedTimeout&&!self.IsLocked()&&++self.iNotLockedCount>self.iNotLockedTimeout) ||
7495 (self.iInactivityTimeout&&++self.iInactivityCount>self.iInactivityTimeout)
7498 DMMCSocket* socket = static_cast<DMMCSocket*>(self.iSocket);
7499 socket->iStack->QSleepStack();
7501 OstTraceFunctionExit0( DMMCPSU_SLEEPCHECK_EXIT );
7504 EXPORT_C DMMCMediaChange::DMMCMediaChange(TInt aMediaChangeNum)
7506 * Constructor for a DMMCMediaChange object
7507 * @param aMediaChangeNum The media change number
7509 : DMediaChangeBase(aMediaChangeNum)
7511 OstTraceFunctionEntryExt( DMMCMEDIACHANGE_DMMCMEDIACHANGE_ENTRY, this );
7514 EXPORT_C TInt DMMCMediaChange::Create()
7516 * Create a DMMCMediaChange object.
7517 * This should be overridden at the variant layer to allow interrupts and
7518 * other variant-specific parameters to be initialised. The base class implementation
7519 * should be called prior to any variant-specific initialisation.
7520 * @return Standard Symbian OS error code.
7523 OstTraceFunctionEntry1( DMMCMEDIACHANGE_CREATE_ENTRY, this );
7524 TInt r = DMediaChangeBase::Create();
7525 OstTraceFunctionExitExt( DMMCMEDIACHANGE_CREATE_EXIT, this, r );