1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1629 @@
1.4 +// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <drivers/sdcard.h>
1.20 +#include "OstTraceDefinitions.h"
1.21 +#ifdef OST_TRACE_COMPILER_IN_USE
1.22 +#include "locmedia_ost.h"
1.23 +#ifdef __VC32__
1.24 +#pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
1.25 +#endif
1.26 +#include "sdcardTraces.h"
1.27 +#endif
1.28 +
1.29 +
1.30 +// ======== TSDCard ========
1.31 +
1.32 +TSDCard::TSDCard()
1.33 +: iProtectedAreaSize(0), iPARootDirEnd(KPARootDirEndUnknown)
1.34 + {
1.35 + // empty
1.36 + }
1.37 +
1.38 +TInt64 TSDCard::DeviceSize64() const
1.39 +//
1.40 +// returns the SD device size
1.41 +//
1.42 + {
1.43 + OstTraceFunctionEntry1( TSDCARD_DEVICESIZE64_ENTRY, this );
1.44 + if(iFlags & KSDCardIsSDCard)
1.45 + {
1.46 + return (IsHighCapacity()) ? 512 * 1024 * (TInt64)(1 + CSD().CSDField(69, 48)) : TMMCard::DeviceSize64();
1.47 + }
1.48 +
1.49 + return(TMMCard::DeviceSize64());
1.50 + }
1.51 +
1.52 +TUint32 TSDCard::PreferredWriteGroupLength() const
1.53 +//
1.54 +// return SD erase sector size, (SECTOR_SIZE + 1) * 2 ** WRITE_BLK_LEN
1.55 +//
1.56 + {
1.57 + OstTraceFunctionEntry1( TSDCARD_PREFERREDWRITEGROUPLENGTH_ENTRY, this );
1.58 + if(iFlags & KSDCardIsSDCard)
1.59 + {
1.60 + TSDCSD sdcsd(CSD());
1.61 + return (sdcsd.SDSectorSize() + 1) * (1 << sdcsd.WriteBlLen());
1.62 + }
1.63 +
1.64 + return(TMMCard::PreferredWriteGroupLength());
1.65 + }
1.66 +
1.67 +TInt TSDCard::GetFormatInfo(TLDFormatInfo& /*aFormatInfo*/) const
1.68 + {
1.69 + return KErrNotSupported;
1.70 + }
1.71 +
1.72 +TUint32 TSDCard::MinEraseSectorSize() const
1.73 + {
1.74 + if(iFlags&KSDCardIsSDCard)
1.75 + {
1.76 + TSDCSD sdcsd(CSD());
1.77 + if (sdcsd.SDEraseBlkEn())
1.78 + return sdcsd.WriteBlockLength(); // raised logarithm
1.79 + else
1.80 + return (sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength();
1.81 + }
1.82 +
1.83 + return TMMCard::MinEraseSectorSize();
1.84 + }
1.85 +
1.86 +
1.87 +const TUint32 KEraseSectorSizeShift = 8; // KEraseSectorSizeShift determines the multiple of the sector size
1.88 + // that can be erased in one operation
1.89 +TUint32 TSDCard::EraseSectorSize() const
1.90 + {
1.91 + if(iFlags&KSDCardIsSDCard)
1.92 + {
1.93 + TSDCSD sdcsd(CSD());
1.94 + return ((sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength()) << KEraseSectorSizeShift;
1.95 + }
1.96 +
1.97 + return TMMCard::EraseSectorSize();
1.98 + }
1.99 +
1.100 +const TInt KDefaultBlockLen = 9; // 2^9 = 512 bytes
1.101 +const TInt KDefaultBlockLenInBytes = 1 << KDefaultBlockLen; // 2^9 = 512 bytes
1.102 +const TInt KTwoGbyteSDBlockLen = 10; // 2^10 = 1024 bytes
1.103 +const TInt KFourGbyteSDBlockLen = 11; // 2^11 = 2048 bytes
1.104 +
1.105 +TInt TSDCard::GetEraseInfo(TMMCEraseInfo& aEraseInfo) const
1.106 +//
1.107 +// Return info. on erase services for this card
1.108 +//
1.109 + {
1.110 + OstTraceFunctionEntry1( TSDCARD_GETERASEINFO_ENTRY, this );
1.111 +
1.112 + // SD Controllers support MMC cards too. Check if we are really dealing with an SD card
1.113 + if(!(iFlags&KSDCardIsSDCard))
1.114 + return(TMMCard::GetEraseInfo(aEraseInfo));
1.115 +
1.116 + if (CSD().CCC() & KMMCCmdClassErase)
1.117 + {
1.118 + // This card supports erase cmds. However, SD cards don't support Erase Group commands (i.e. CMD35, CMD36).
1.119 + OstTrace0( TRACE_INTERNALS, TSDCARD_GETERASEINFO, "Card supports erase class commands" );
1.120 + aEraseInfo.iEraseFlags=KMMCEraseClassCmdsSupported;
1.121 +
1.122 + // Return the preferred size to be used as the unit for erase operations.
1.123 + TSDCSD sdcsd(CSD());
1.124 + TUint32 prefSize=((sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength());
1.125 + prefSize<<=KEraseSectorSizeShift; // Use multiples of the sector size for each erase operation
1.126 + aEraseInfo.iPreferredEraseUnitSize=prefSize;
1.127 +
1.128 + // Return the smallest size that can be used as the unit for erase operations
1.129 + if (sdcsd.SDEraseBlkEn())
1.130 + {
1.131 + aEraseInfo.iMinEraseSectorSize = KDefaultBlockLenInBytes;
1.132 + }
1.133 + else
1.134 + {
1.135 + aEraseInfo.iMinEraseSectorSize=(sdcsd.SDSectorSize() + 1) * sdcsd.WriteBlockLength();
1.136 + }
1.137 + }
1.138 + else
1.139 + aEraseInfo.iEraseFlags=0;
1.140 +
1.141 + OstTraceFunctionExitExt( TSDCARD_GETERASEINFO_EXIT, this, KErrNone );
1.142 + return KErrNone;
1.143 + }
1.144 +
1.145 +TInt TSDCard::MaxReadBlLen() const
1.146 +/**
1.147 + * Returns the maximum read block length supported by the card encoded as a logarithm
1.148 + * Normally this is the same as the READ_BL_LEN field in the CSD register,
1.149 + * but for high capacity cards (> 2GB) this is set to a maximum of 512 bytes,
1.150 + * if possible, to try to avoid compatibility issues.
1.151 + */
1.152 + {
1.153 + OstTraceFunctionEntry1( TSDCARD_MAXREADBLLEN_ENTRY, this );
1.154 + if (IsSDCard())
1.155 + {
1.156 + TInt blkLenLog2 = CSD().ReadBlLen();
1.157 + if (blkLenLog2 == KTwoGbyteSDBlockLen || blkLenLog2 == KFourGbyteSDBlockLen)
1.158 + {
1.159 + // The SD card spec. makes a special case for 2GByte cards,
1.160 + // ...and some manufacturers apply the same method to support 4G cards
1.161 + __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mrbl > 2GB SD"));
1.162 + OstTrace0( TRACE_INTERNALS, TSDCARD_MAXREADBLLEN, "SD Card > 2GB" );
1.163 + blkLenLog2 = KDefaultBlockLen;
1.164 + }
1.165 + OstTraceFunctionExitExt( TSDCARD_MAXREADBLLEN_EXIT, this, blkLenLog2 );
1.166 + return blkLenLog2;
1.167 + }
1.168 + else // MMC card
1.169 + {
1.170 + TInt ret = TMMCard::MaxReadBlLen();
1.171 + OstTraceFunctionExitExt( DUP1_TSDCARD_MAXREADBLLEN_EXIT, this, ret );
1.172 + return ret;
1.173 + }
1.174 + }
1.175 +
1.176 +TInt TSDCard::MaxWriteBlLen() const
1.177 +/**
1.178 + * Returns the maximum write block length supported by the card encoded as a logarithm
1.179 + * Normally this is the same as the WRITE_BL_LEN field in the CSD register,
1.180 + * but for high capacity cards (> 2GB) this is set to a maximum of 512 bytes,
1.181 + * if possible, to try to avoid compatibility issues.
1.182 + */
1.183 + {
1.184 + OstTraceFunctionEntry1( TSDCARD_MAXWRITEBLLEN_ENTRY, this );
1.185 + if (IsSDCard())
1.186 + {
1.187 + TInt blkLenLog2 = CSD().WriteBlLen();
1.188 + if (blkLenLog2 == KTwoGbyteSDBlockLen || blkLenLog2 == KFourGbyteSDBlockLen)
1.189 + {
1.190 + // The SD card spec. makes a special case for 2GByte cards,
1.191 + // ...and some manufacturers apply the same method to support 4G cards
1.192 + __KTRACE_OPT(KPBUS1, Kern::Printf("=mmc:mwbl > 2GB SD"));
1.193 + OstTrace0( TRACE_INTERNALS, TSDCARD_MAXWRITEBLLEN, "SD Card > 2GB" );
1.194 + blkLenLog2 = KDefaultBlockLen;
1.195 + }
1.196 + OstTraceFunctionExitExt( TSDCARD_MAXWRITEBLLEN_EXIT, this, blkLenLog2 );
1.197 + return blkLenLog2;
1.198 + }
1.199 + else // MMC card
1.200 + {
1.201 + TInt ret = TMMCard::MaxWriteBlLen();
1.202 + OstTraceFunctionExitExt( DUP1_TSDCARD_MAXWRITEBLLEN_EXIT, this, ret );
1.203 + return ret;
1.204 + }
1.205 + }
1.206 +
1.207 +TUint TSDCard::MaxTranSpeedInKilohertz() const
1.208 +/**
1.209 + * Returns the maximum supported clock rate for the card, in Kilohertz.
1.210 + * @return Speed, in Kilohertz
1.211 + */
1.212 + {
1.213 + OstTraceFunctionEntry1( TSDCARD_MAXTRANSPEEDINKILOHERTZ_ENTRY, this );
1.214 + TUint maxClk = TMMCard::MaxTranSpeedInKilohertz();
1.215 +
1.216 + if (IsSDCard())
1.217 + {
1.218 + __KTRACE_OPT(KPBUS1, Kern::Printf("\t >TSDCard(%d): MaxTranSpeedInKilohertz: %d",(iIndex-1),maxClk));
1.219 +
1.220 +#ifdef _DEBUG
1.221 + //MaxClk for SD should only be either 25000KHz or 50000KHz
1.222 + if ( (maxClk != KSDDTClk25MHz) && (maxClk != KSDDTClk50MHz) )
1.223 + {
1.224 + __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Non-Compliant DT Clock"));
1.225 + OstTrace0( TRACE_INTERNALS, TSDCARD_MAXTRANSPEEDINKILOHERTZ, "Non-Compliant DT Clock" );
1.226 + }
1.227 +#endif
1.228 + if (maxClk > KSDDTClk50MHz)
1.229 + {
1.230 + //Clock rate exceeds SD possible max clock rate
1.231 + __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Tuning DT Clock down to 50MHz"));
1.232 + OstTrace0( TRACE_INTERNALS, TSDCARD_MAXTRANSPEEDINKILOHERTZ1, "Tuning DT Clock down to 50MHz" );
1.233 + maxClk = KSDDTClk50MHz;
1.234 + }
1.235 + }
1.236 +
1.237 + OstTraceFunctionExitExt( TSDCARD_MAXTRANSPEEDINKILOHERTZ_EXIT, this, maxClk );
1.238 + return maxClk;
1.239 + }
1.240 +
1.241 +// ======== TSDCardArray ========
1.242 +
1.243 +EXPORT_C TInt TSDCardArray::AllocCards()
1.244 +//
1.245 +// allocate TSDCard objects for iCards and iNewCardsArray. This function
1.246 +// is called at bootup as part of stack allocation so there is no cleanup
1.247 +// if it fails.
1.248 +//
1.249 + {
1.250 + OstTraceFunctionEntry1( TSDCARDARRAY_ALLOCCARDS_ENTRY, this );
1.251 + for (TInt i = 0; i < (TInt) KMaxMMCardsPerStack; ++i)
1.252 + {
1.253 + // zeroing the card data used to be implicit because embedded in
1.254 + // CBase-derived DMMCStack.
1.255 + if ((iCards[i] = new TSDCard) == 0)
1.256 + {
1.257 + OstTraceFunctionExitExt( TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNoMemory );
1.258 + return KErrNoMemory;
1.259 + }
1.260 + iCards[i]->iUsingSessionP = 0;
1.261 + if ((iNewCards[i] = new TSDCard) == 0)
1.262 + {
1.263 + OstTraceFunctionExitExt( DUP1_TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNoMemory );
1.264 + return KErrNoMemory;
1.265 + }
1.266 + }
1.267 +
1.268 + OstTraceFunctionExitExt( DUP2_TSDCARDARRAY_ALLOCCARDS_EXIT, this, KErrNone );
1.269 + return KErrNone;
1.270 + }
1.271 +
1.272 +void TSDCardArray::AddCardSDMode(TUint aCardNumber,const TUint8* aCID,TRCA* aNewRCA)
1.273 +//
1.274 +// Add an MMC card straight to the main card array in slot 'aCardNumber'. Save
1.275 +// the CID value in the slot. Return a RCA for the card.
1.276 +//
1.277 + {
1.278 + OstTraceFunctionEntryExt( TSDCARDARRAY_ADDCARDSDMODE_ENTRY, this );
1.279 +
1.280 + TRCA rca=0;
1.281 +
1.282 + // First, lets check if the same card was here before. If it was, keep the same RCA
1.283 + if (Card(aCardNumber).IsPresent() && Card(aCardNumber).iCID==aCID)
1.284 + rca=Card(aCardNumber).iRCA;
1.285 + else
1.286 + {
1.287 + // Allocate and new RCA and store the CID in the slot selected
1.288 + __ASSERT_ALWAYS( (rca=iOwningStack->iRCAPool.GetFreeRCA())!=0,DMMCSocket::Panic(DMMCSocket::EMMCNoFreeRCA) );
1.289 + Card(aCardNumber).iCID=aCID;
1.290 + if ( Card(aCardNumber).iRCA != 0 )
1.291 + iOwningStack->iRCAPool.UnlockRCA(Card(aCardNumber).iRCA);
1.292 + Card(aCardNumber).iRCA=rca;
1.293 + iOwningStack->iRCAPool.LockRCA(Card(aCardNumber).iRCA);
1.294 + }
1.295 +
1.296 + Card(aCardNumber).iIndex=(aCardNumber+1); // Mark card as being present
1.297 + *aNewRCA=rca;
1.298 + OstTraceFunctionExit1( TSDCARDARRAY_ADDCARDSDMODE_EXIT, this );
1.299 + }
1.300 +
1.301 +TInt TSDCardArray::StoreRCAIfUnique(TUint aCardNumber,TRCA& anRCA)
1.302 +//
1.303 +// Check that no other array element has the same RCA value 'anRCA'. If no
1.304 +// no duplication then store in slot 'aCardNumber'.
1.305 +//
1.306 + {
1.307 + OstTraceExt3(TRACE_FLOW, TSDCARDARRAY_STORERCAIFUNIQUE_ENTRY ,"TSDCardArray::StoreRCAIfUnique;aCardNumber=%x;anRCA=%x;this=%x", aCardNumber, (TUint) anRCA, (TUint) this);
1.308 +
1.309 + if (anRCA==0)
1.310 + {
1.311 + OstTraceFunctionExitExt( TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrGeneral );
1.312 + return KErrGeneral;
1.313 + }
1.314 + Card(aCardNumber).iRCA=0;
1.315 +
1.316 + // Now let's look if we've seen this card before
1.317 + for ( TUint i=0 ; i<iOwningStack->iMaxCardsInStack ; i++ )
1.318 + {
1.319 + if ( Card(i).IsPresent() && Card(i).iRCA==anRCA )
1.320 + {
1.321 + OstTraceFunctionExitExt( DUP1_TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrInUse );
1.322 + return KErrInUse;
1.323 + }
1.324 + }
1.325 + Card(aCardNumber).iRCA=anRCA;
1.326 + Card(aCardNumber).iIndex=(aCardNumber+1); // Mark card as being present
1.327 + OstTraceFunctionExitExt( DUP2_TSDCARDARRAY_STORERCAIFUNIQUE_EXIT, this, KErrNone );
1.328 + return KErrNone;
1.329 + }
1.330 +
1.331 +EXPORT_C void TSDCardArray::DeclareCardAsGone(TUint aCardNumber)
1.332 +//
1.333 +// reset SD specific fields to initial values and then reset generic MultiMediaCard
1.334 +//
1.335 + {
1.336 + OstTraceFunctionEntryExt( TSDCARDARRAY_DECLARECARDASGONE_ENTRY, this );
1.337 + Card(aCardNumber).SetBusWidth(1);
1.338 + TMMCardArray::DeclareCardAsGone(aCardNumber);
1.339 + OstTraceFunctionExit1( TSDCARDARRAY_DECLARECARDASGONE_EXIT, this );
1.340 + }
1.341 +
1.342 +// ======== DSDSession ========
1.343 +
1.344 +void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc, TSDAppCmd aCmd)
1.345 + {
1.346 + OstTraceFunctionEntry0( DSDSESSION_FILLAPPCOMMANDDESC_ENTRY );
1.347 + aDesc.iCommand = (TMMCCommandEnum) aCmd;
1.348 + aDesc.iArgument = 0; // set stuff bits to zero
1.349 + FillAppCommandDesc(aDesc);
1.350 + OstTraceFunctionExit0( DSDSESSION_FILLAPPCOMMANDDESC_EXIT );
1.351 + }
1.352 +
1.353 +void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc, TSDAppCmd aCmd, TMMCArgument aArg)
1.354 + {
1.355 + OstTraceFunctionEntry0( DUP1_DSDSESSION_FILLAPPCOMMANDDESC_ENTRY );
1.356 + aDesc.iCommand = (TMMCCommandEnum) aCmd;
1.357 + aDesc.iArgument = aArg;
1.358 + FillAppCommandDesc(aDesc);
1.359 + OstTraceFunctionExit0( DUP1_DSDSESSION_FILLAPPCOMMANDDESC_EXIT );
1.360 + }
1.361 +
1.362 +const TUint32 CCA = KMMCCmdClassApplication;
1.363 +const TMMCIdxCommandSpec AppCmdSpecTable[] =
1.364 + { // Class Type Dir MBlk StopT Rsp Type Len
1.365 + {ESDACmdSetBusWidth, {CCA,ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD6
1.366 + {ESDACmdSDStatus, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD13
1.367 + {ESDACmdSendNumWrBlocks, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD22
1.368 + {ESDACmdSetWrBlkEraseCount, {CCA,ECmdTypeACS, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD23
1.369 + {ESDACmdSDAppOpCond, {CCA,ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR3, 4}}, //ACMD41
1.370 + {ESDACmdSetClrCardDetect, {CCA,ECmdTypeAC, EDirNone, EFalse, EFalse, ERespTypeR1, 4}}, //ACMD42
1.371 + {ESDACmdSendSCR, {CCA,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}} //ACMD51
1.372 +};
1.373 +
1.374 +void DSDSession::FillAppCommandDesc(TMMCCommandDesc& aDesc)
1.375 + {
1.376 + OstTraceFunctionEntry0( DUP2_DSDSESSION_FILLAPPCOMMANDDESC_ENTRY );
1.377 + aDesc.iSpec = FindCommandSpec(AppCmdSpecTable, aDesc.iCommand);
1.378 + aDesc.iFlags = 0;
1.379 + aDesc.iBytesDone = 0;
1.380 + OstTraceFunctionExit0( DUP2_DSDSESSION_FILLAPPCOMMANDDESC_EXIT );
1.381 + }
1.382 +
1.383 +const TMMCIdxCommandSpec SdSpecificCmdSpecTable[] =
1.384 +/**
1.385 + * SD Specific Command Table
1.386 + *
1.387 + * - Some commands defined in the SD specification overload those defined in the MMC specification.
1.388 + * This table contains the SD specific versions of those commands.
1.389 + */
1.390 + {
1.391 + // Class Type Dir MBlk StopT Rsp Type Len
1.392 + {ESDCmdSendRelativeAddress, {KMMCCmdClassBasic, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR6, 4}}, // CMD3 : SEND_RELATIVE_ADDRESS
1.393 + {ESDCmdSwitchFunction, {KMMCCmdClassSwitch,ECmdTypeADTCS, EDirRead, EFalse, EFalse, ERespTypeR1, 4}}, // CMD6 : SWITCH_FUNCTION
1.394 + {ESDCmdSendIfCond, {KMMCCmdClassBasic, ECmdTypeBCR, EDirNone, EFalse, EFalse, ERespTypeR7, 4}} // CMD8 : SEND_IF_COND
1.395 + };
1.396 +
1.397 +void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc, TSDSpecificCmd aCmd, TMMCArgument aArg)
1.398 + {
1.399 + OstTraceFunctionEntry0( DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY );
1.400 + aDesc.iCommand = (TMMCCommandEnum) aCmd;
1.401 + aDesc.iArgument = aArg;
1.402 + FillSdSpecificCommandDesc(aDesc);
1.403 + OstTraceFunctionExit0( DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT );
1.404 + }
1.405 +
1.406 +void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc, TSDSpecificCmd aCmd)
1.407 + {
1.408 + OstTraceFunctionEntry0( DUP1_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY );
1.409 + aDesc.iCommand = (TMMCCommandEnum) aCmd;
1.410 + aDesc.iArgument = 0; // set stuff bits to zero
1.411 + FillSdSpecificCommandDesc(aDesc);
1.412 + OstTraceFunctionExit0( DUP1_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT );
1.413 + }
1.414 +
1.415 +void DSDSession::FillSdSpecificCommandDesc(TMMCCommandDesc& aDesc)
1.416 + {
1.417 + OstTraceFunctionEntry0( DUP2_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_ENTRY );
1.418 + aDesc.iSpec = FindCommandSpec(SdSpecificCmdSpecTable, aDesc.iCommand);
1.419 + aDesc.iFlags = 0;
1.420 + aDesc.iBytesDone = 0;
1.421 + OstTraceFunctionExit0( DUP2_DSDSESSION_FILLSDSPECIFICCOMMANDDESC_EXIT );
1.422 + }
1.423 +
1.424 +
1.425 +// ======== DSDStack ========
1.426 +
1.427 +EXPORT_C TInt DSDStack::Init()
1.428 + {
1.429 + OstTraceFunctionEntry1( DSDSTACK_INIT_ENTRY, this );
1.430 + TInt ret = DMMCStack::Init();
1.431 + OstTraceFunctionExitExt( DSDSTACK_INIT_EXIT, this, ret );
1.432 + return ret;
1.433 + }
1.434 +
1.435 +
1.436 +const TInt KMaxRCASendLoops=3;
1.437 +const TUint KSDMaxPollAttempts=25;
1.438 +EXPORT_C TMMCErr DSDStack::AcquireStackSM()
1.439 +//
1.440 +// This macro acquires new cards in an SD Card - star topology stack.
1.441 +// This means each card has its own CMD and DAT lines and can be addressed
1.442 +// individually by the Controller in turn. Commands can also be broadcast
1.443 +// simultaneously to the entire stack.
1.444 +// It starts with the Controller reading the operating conditions of each
1.445 +// card in the stack (SEND_OP_COND - ACMD41). Then, the following
1.446 +// initialisation sequence is performed to each card in turn:-
1.447 +// New cards in the stack are identified (ALL_SEND_CID - CMD2) and each one
1.448 +// is requested to publish a relative card address (SEND_RCA - CMD3). Finally,
1.449 +// the card specific data (SEND_CSD - CMD9) is read from each card.
1.450 +// Note that the initialization of MMC cards are supported by this function
1.451 +// if they are encountered. These require a slightly different init. procdure.
1.452 +//
1.453 + {
1.454 + enum states
1.455 + {
1.456 + EStBegin=0,
1.457 + EStNextFullRange,
1.458 + EStSendCIDIssued,
1.459 + EStIssueSendRCA,
1.460 + EStSendRCACheck,
1.461 + EStRCADone,
1.462 + EStMoreCardsCheck,
1.463 + EStEnd
1.464 + };
1.465 +
1.466 + DMMCSession& s=Session();
1.467 + OstTrace1( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM, "Current session = 0x%x", &s );
1.468 +
1.469 + SMF_BEGIN
1.470 +
1.471 + OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM1, "EStBegin" );
1.472 + __KTRACE_OPT(KPBUS1, Kern::Printf(">DSDStack::AcquireStackSM()"));
1.473 +
1.474 + iRCAPool.ReleaseUnlocked();
1.475 + iCxCardCount=0; // Reset current card number
1.476 +
1.477 + SMF_STATE(EStNextFullRange)
1.478 +
1.479 + OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM2, "EStNextFullRange" );
1.480 + iCxCardType = ESDCardTypeUnknown;
1.481 +
1.482 + AddressCard(iCxCardCount); // Address the next card
1.483 +
1.484 + // Before issueing commands, see if there's actually a card present
1.485 + if (!CardDetect(iCxCardCount))
1.486 + SMF_GOTOS(EStMoreCardsCheck)
1.487 +
1.488 + m.SetTraps(KMMCErrResponseTimeOut);
1.489 + SMF_INVOKES(InitialiseMemoryCardSMST, EStSendCIDIssued)
1.490 +
1.491 + SMF_STATE(EStSendCIDIssued)
1.492 +
1.493 + OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM3, "EStSendCIDIssued" );
1.494 + if( !err )
1.495 + {
1.496 + // The card responded with a CID. We need to initialise the
1.497 + // appropriate entry in the card array with the CID.
1.498 + if (iCxCardType==ESDCardTypeIsSD)
1.499 + {
1.500 + // Now prepare to recieve an RCA from to the card
1.501 + CardArray().CardP(iCxCardCount)->iCID=s.ResponseP();
1.502 + DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSendRelativeAddress,0); // SEND_RCA with argument just stuff bits
1.503 +
1.504 + m.ResetTraps();
1.505 + iCxPollRetryCount=0; // Init count of send RCA attempts
1.506 + SMF_GOTOS(EStIssueSendRCA)
1.507 + }
1.508 + else
1.509 + {
1.510 + // The card array allocates an RCA, either the old RCA
1.511 + // if we have seen this card before, or a new one.
1.512 + TRCA rca;
1.513 + CardArray().AddCardSDMode(iCxCardCount,s.ResponseP(),&rca);
1.514 +
1.515 + // Now assign the new RCA to the card
1.516 + s.FillCommandDesc(ECmdSetRelativeAddr,TMMCArgument(rca));
1.517 + m.ResetTraps();
1.518 + SMF_INVOKES(ExecCommandSMST,EStRCADone)
1.519 + }
1.520 + }
1.521 + else
1.522 + {
1.523 + m.ResetTraps();
1.524 + SMF_GOTOS(EStMoreCardsCheck) // Timed out, try the next card slot
1.525 + }
1.526 +
1.527 + SMF_STATE(EStIssueSendRCA)
1.528 +
1.529 + OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM4, "EStIssueSendRCA" );
1.530 + SMF_INVOKES(ExecCommandSMST,EStSendRCACheck)
1.531 +
1.532 + SMF_STATE(EStSendRCACheck)
1.533 +
1.534 + OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM5, "EStSendRCACheck" );
1.535 + // We need to check that the RCA recieved from the card doesn't clash
1.536 + // with any others in this stack. RCA is first 2 bytes of response buffer (in big endian)
1.537 + TRCA rca=(TUint16)((s.ResponseP()[0]<<8) | s.ResponseP()[1]);
1.538 + if (CardArray().StoreRCAIfUnique(iCxCardCount,rca)!=KErrNone)
1.539 + SMF_GOTOS( ((++iCxPollRetryCount<KMaxRCASendLoops)?EStIssueSendRCA:EStMoreCardsCheck) )
1.540 +
1.541 + SMF_STATE(EStRCADone)
1.542 +
1.543 + OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM6, "EStRCADone" );
1.544 + SMF_INVOKES(ConfigureMemoryCardSMST, EStMoreCardsCheck)
1.545 +
1.546 + SMF_STATE(EStMoreCardsCheck)
1.547 +
1.548 + OstTrace0( TRACE_INTERNALS, DSDSTACK_ATTACHCARDSM7, "EStMoreCardsCheck" );
1.549 + if (++iCxCardCount < (TInt)iMaxCardsInStack)
1.550 + {
1.551 + __KTRACE_OPT(KPBUS1, Kern::Printf(">DSDStack::AcquireStackSM(): More Cards to check: %d",iCxCardCount));
1.552 + OstTrace1( TRACE_INTERNALS, DSDSTACK_ACQUIRESTACKSM8, "More Cards to check: iCxCardCount=%d", iCxCardCount );
1.553 + SMF_GOTOS(EStNextFullRange)
1.554 + }
1.555 + else
1.556 + {
1.557 + AddressCard(KBroadcastToAllCards); // Set back to broadcast mode
1.558 + __KTRACE_OPT(KPBUS1, Kern::Printf("<DSDStack::AcquireStackSM()"));
1.559 + }
1.560 +
1.561 + SMF_END
1.562 + }
1.563 +
1.564 +
1.565 +TMMCErr DSDStack::InitialiseMemoryCardSMST(TAny* aStackP)
1.566 + { return static_cast<DSDStack*>(aStackP)->InitialiseMemoryCardSM(); }
1.567 +
1.568 +
1.569 +TMMCErr DSDStack::InitialiseMemoryCardSM()
1.570 +/**
1.571 +*/
1.572 + {
1.573 + enum states
1.574 + {
1.575 + EStBegin=0,
1.576 + EStSendInterfaceCondition,
1.577 + EStSentInterfaceCondition,
1.578 + EStSetFullRangeCmd,
1.579 + EStCheckForFullRangeCmd41Timeout,
1.580 + EStSentAppCommandBeforeCheckVoltage,
1.581 + EStCheckVoltage,
1.582 + EStFullRangeDone,
1.583 + EStSetRangeCmd,
1.584 + EStCheckForRangeCmd41Timeout,
1.585 + EStSetRangeBusyCheck,
1.586 + EStCIDCmd,
1.587 + EStSendCIDIssued,
1.588 + EStEnd
1.589 + };
1.590 +
1.591 + DMMCSession& s=Session();
1.592 + DMMCPsu* psu=(DMMCPsu*)MMCSocket()->iVcc;
1.593 + OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM, "Current session = 0x%x", &s );
1.594 +
1.595 + static const TUint32 KCmd8Param = 0x0100 | 0x00AA; // Voltage supplied : 2.7-3.6V, Check Pattern 10101010b
1.596 + static const TUint32 KCmd8CheckMask = 0x00000FFF;
1.597 +
1.598 + SMF_BEGIN
1.599 +
1.600 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM1, "EStBegin" );
1.601 + iCxCardType = ESDCardTypeUnknown;
1.602 + s.iCardP = NULL; // This stops ExecCommandSM() from setting old RCA when sending CMD55
1.603 +
1.604 + // Send CMD0 to initialise memory
1.605 + SMF_INVOKES(GoIdleSMST, EStSendInterfaceCondition);
1.606 +
1.607 + SMF_STATE(EStSendInterfaceCondition)
1.608 +
1.609 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM2, "EStSendInterfaceCondition" );
1.610 + iCxPollRetryCount=0; // Reset max number of poll attempts on card busy
1.611 + iConfig.SetPollAttempts(KSDMaxPollAttempts); // Increase card busy timeout to 1 Sec for SD Cards
1.612 +
1.613 + iConfig.RemoveMode( KMMCModeEnableTimeOutRetry ); // Temporarily disable timeout retries - since we use a timeout event to distinguish between MMC and SD
1.614 +
1.615 + DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSendIfCond, KCmd8Param);
1.616 +
1.617 + // SD2.0 defines CMD8 as having a new response type - R7
1.618 + // if the PSL doesn't indicate support for R7, use R1 instead
1.619 + if (!(MMCSocket()->MachineInfo().iFlags & TMMCMachineInfo::ESupportsR7))
1.620 + {
1.621 + __KTRACE_OPT(KPBUS1, Kern::Printf("R7 not supported."));
1.622 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM3, "R7 not supported" );
1.623 + Command().iSpec.iResponseType = ERespTypeR1;
1.624 + }
1.625 +
1.626 +
1.627 + m.SetTraps(KMMCErrAll);
1.628 + SMF_INVOKES(ExecCommandSMST, EStSentInterfaceCondition)
1.629 +
1.630 + SMF_STATE(EStSentInterfaceCondition)
1.631 +
1.632 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM4, "EStSentInterfaceCondition" );
1.633 + if (err == KMMCErrNone)
1.634 + {
1.635 + // Check the response for voltage and check pattern
1.636 + const TUint32 status = TMMC::BigEndian32(s.ResponseP());
1.637 + if((status & KCmd8CheckMask) == KCmd8Param)
1.638 + {
1.639 + __KTRACE_OPT(KPBUS1, Kern::Printf("Found v2 card."));
1.640 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM5, "Found v2 card" );
1.641 + iCurrentOpRange |= KMMCOCRAccessModeHCS;
1.642 + }
1.643 + else
1.644 + {
1.645 + // Pattern Mis-match, card does not support the specified voltage range
1.646 + OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT, this, (TInt) KMMCErrNotSupported );
1.647 + return KMMCErrNotSupported;
1.648 + }
1.649 +
1.650 + SMF_GOTOS(EStCheckVoltage);
1.651 + }
1.652 +
1.653 + // Go idle again after CMD8 failure
1.654 + SMF_INVOKES(GoIdleSMST, EStCheckVoltage);
1.655 +
1.656 +
1.657 + SMF_STATE(EStCheckVoltage)
1.658 +
1.659 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM6, "EStCheckVoltage" );
1.660 + // If platform doesn't support an adjustable voltage PSU then there's no
1.661 + // point in doing a full range for its supported range. To support range
1.662 + // checking on a multi-card stack would require a complete scan of all
1.663 + // cards before actually setting the range. This would over-complicate things
1.664 + // and make the more normal single card/none adjustable cases less efficient.
1.665 + if ( !(psu->VoltageSupported()&KMMCAdjustableOpVoltage) || iMaxCardsInStack>1)
1.666 + {
1.667 + // if the PSU isn't adjustable then it can't support low voltage mode
1.668 + iCurrentOpRange&= ~KMMCOCRLowVoltage;
1.669 +
1.670 + SMF_GOTOS(EStSetRangeCmd)
1.671 + }
1.672 +
1.673 + SMF_STATE(EStSetFullRangeCmd)
1.674 +
1.675 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM7, "EStSetFullRangeCmd" );
1.676 + // Issue ACMD41/CMD1 with omitted voltage range
1.677 + if (iCxCardType==ESDCardTypeIsMMC)
1.678 + {
1.679 + s.FillCommandDesc(ECmdSendOpCond, KMMCOCRAccessModeHCS | KMMCOCRBusy); // Full range + Sector Access + Busy bit (iArgument==KBit31)
1.680 + SMF_NEXTS(EStFullRangeDone)
1.681 + }
1.682 + else
1.683 + {
1.684 + DSDSession::FillAppCommandDesc(Command(), ESDACmdSDAppOpCond, TMMCArgument(0));
1.685 + SMF_NEXTS(EStCheckForFullRangeCmd41Timeout)
1.686 + }
1.687 +
1.688 + m.SetTraps(KMMCErrResponseTimeOut);
1.689 + SMF_CALL(ExecCommandSMST)
1.690 +
1.691 + SMF_STATE(EStCheckForFullRangeCmd41Timeout)
1.692 +
1.693 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM8, "EStCheckForFullRangeCmd41Timeout" );
1.694 + if (err==KMMCErrResponseTimeOut)
1.695 + {
1.696 + __KTRACE_OPT(KPBUS1, Kern::Printf("ACMD 41 not supported - Assuming MMC"));
1.697 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM9, "ACMD 41 not supported - Assuming MMC" );
1.698 + iCxCardType=ESDCardTypeIsMMC;
1.699 +
1.700 + // Send CMD0 to re-initialise the card - otherwise we may get
1.701 + // KMMCStatErrIllegalCommand returned for the next command
1.702 + // expecting an R1 response. NB The SD spec recommends ignoring the error
1.703 + // whereas the SDIO spec recommends this approach (ignoring the error
1.704 + // would be difficult to code anyway, since by then we're no longer
1.705 + // in this state machine).
1.706 + SMF_INVOKES(GoIdleSMST, EStSetFullRangeCmd); // Repeat - but using CMD1
1.707 + }
1.708 + else
1.709 + {
1.710 + // No response timeout - so it must be an SD Card
1.711 + (CardArray().CardP(iCxCardCount)->iFlags)|=KSDCardIsSDCard;
1.712 + iCxCardType=ESDCardTypeIsSD;
1.713 + }
1.714 +
1.715 + SMF_STATE(EStFullRangeDone)
1.716 +
1.717 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM10, "EStFullRangeDone" );
1.718 + if (!err)
1.719 + {
1.720 + // Card responded with Op range - evaluate the common subset with the current setting.
1.721 + // Dont worry about the busy bit for now, we'll check that when we repeat the command
1.722 + const TUint32 range = (iCurrentOpRange & ~KMMCOCRAccessModeHCS) & (TMMC::BigEndian32(s.ResponseP()) & ~KMMCOCRBusy);
1.723 + if(range == 0)
1.724 + {
1.725 + OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT1, this, (TInt) KMMCErrNotSupported );
1.726 + return KMMCErrNotSupported; // Card is incompatible with our h/w
1.727 + }
1.728 + iCurrentOpRange = range | (iCurrentOpRange & KMMCOCRAccessModeHCS);
1.729 + }
1.730 +
1.731 + // Repeat SEND_OP_COND this time setting Current Op Range
1.732 + if (iCxCardType==ESDCardTypeIsMMC)
1.733 + {
1.734 + // If platform and the card both support low voltage mode (1.65 - 1.95v), switch
1.735 + // NB If this fails then there is no recovery.
1.736 + if (iCurrentOpRange & KMMCOCRLowVoltage)
1.737 + {
1.738 + iCurrentOpRange = KMMCOCRLowVoltage;
1.739 + SMF_INVOKES( SwitchToLowVoltageSMST, EStSetRangeCmd )
1.740 + }
1.741 + }
1.742 +
1.743 + SMF_STATE(EStSetRangeCmd)
1.744 +
1.745 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM11, "EStSetRangeCmd" );
1.746 + // Issue ACMD41/CMD1 with voltage range
1.747 + if (iCxCardType==ESDCardTypeIsMMC)
1.748 + {
1.749 + s.FillCommandDesc(ECmdSendOpCond,(iCurrentOpRange | KMMCOCRAccessModeHCS | KMMCOCRBusy)); // Range supported + Sector Access Busy bit (iArgument==KBit31)
1.750 + SMF_NEXTS(EStSetRangeBusyCheck)
1.751 + }
1.752 + else
1.753 + {
1.754 + TUint arg = (iCurrentOpRange & ~KMMCOCRAccessModeHCS); // Range supported
1.755 + if((iCurrentOpRange & KMMCOCRAccessModeHCS) != 0)
1.756 + {
1.757 + arg |= KMMCOCRAccessModeHCS;
1.758 + }
1.759 + DSDSession::FillAppCommandDesc(Command(), ESDACmdSDAppOpCond, arg);
1.760 + SMF_NEXTS((iCxCardType == ESDCardTypeUnknown)? EStCheckForRangeCmd41Timeout : EStSetRangeBusyCheck)
1.761 + }
1.762 +
1.763 + m.SetTraps(KMMCErrResponseTimeOut);
1.764 + SMF_CALL(ExecCommandSMST)
1.765 +
1.766 + SMF_STATE(EStCheckForRangeCmd41Timeout)
1.767 +
1.768 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM12, "EStCheckForRangeCmd41Timeout" );
1.769 + __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct:%d", err));
1.770 + OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM13, "err=%d", (TInt) err);
1.771 + if (err==KMMCErrResponseTimeOut)
1.772 + {
1.773 + iCxCardType=ESDCardTypeIsMMC;
1.774 + // Send CMD0 to re-initialise the card - otherwise we may get
1.775 + // KMMCStatErrIllegalCommand returned for the next command
1.776 + // expecting an R1 response. NB The SD spec recommends ignoring the error
1.777 + // whereas the SDIO spec recommends this approach (ignoring the error
1.778 + // would be difficult to code anyway, since by then we're no longer
1.779 + // in this state machine).
1.780 + SMF_INVOKES(GoIdleSMST, EStSetRangeCmd); // Repeat - but using CMD1
1.781 + }
1.782 + else
1.783 + {
1.784 + // No response timeout - so it must be an SD Card
1.785 + __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct2:%x", iCardArray));
1.786 + __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct3:%x", iCxCardCount));
1.787 + __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:crct4:%x", CardArray().CardP(iCxCardCount)));
1.788 + OstTraceExt3(TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM14, "iCardArray=0x%x;iCxCardCount=%d;CardArray().CardP(iCxCardCount)=%d", (TUint) iCardArray, (TInt) iCxCardCount, (TInt) CardArray().CardP(iCxCardCount));
1.789 +
1.790 + (CardArray().CardP(iCxCardCount)->iFlags)|=KSDCardIsSDCard;
1.791 + iCxCardType=ESDCardTypeIsSD;
1.792 + }
1.793 +
1.794 + SMF_STATE(EStSetRangeBusyCheck)
1.795 +
1.796 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM15, "EStSetRangeBusyCheck" );
1.797 + __KTRACE_OPT(KPBUS1, Kern::Printf("-mst:ascs:src:%d",iCxCardType)); // 1:MMC, 2:SD
1.798 + OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM16, "iCxCardType=%d", iCxCardType);
1.799 +
1.800 + if ( !err )
1.801 + {
1.802 + const TUint32 ocrResponse = TMMC::BigEndian32(s.ResponseP());
1.803 +
1.804 + if ((ocrResponse & KMMCOCRBusy) == 0)
1.805 + {
1.806 + __KTRACE_OPT(KPBUS1,Kern::Printf("-sd:upd:bsy"));
1.807 + // Card is still busy powering up. Check if we should timeout
1.808 + if ( ++iCxPollRetryCount > iConfig.OpCondBusyTimeout() )
1.809 + {
1.810 + __KTRACE_OPT2(KPBUS1, KPANIC, Kern::Printf("-sd:ocr busy timed out"));
1.811 + OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT2, this, (TInt) KMMCErrBusTimeOut );
1.812 + return KMMCErrBusTimeOut;
1.813 + }
1.814 +
1.815 +#ifdef _DEBUG
1.816 + if ( iCxPollRetryCount > KMMCSpecOpCondBusyTimeout )
1.817 + {
1.818 + __KTRACE_OPT2(KPBUS1, KPANIC, Kern::Printf("-sd:ocr exceeded spec timeout!! (%d ms)", (iCxPollRetryCount*KMMCRetryGapInMilliseconds)));
1.819 + OstTrace1( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM17, "Exceeded spec timeout (%d ms)", (iCxPollRetryCount*KMMCRetryGapInMilliseconds));
1.820 + }
1.821 +#endif
1.822 + m.ResetTraps();
1.823 +
1.824 + SMF_INVOKES(RetryGapTimerSMST,EStSetRangeCmd)
1.825 + }
1.826 + else
1.827 + {
1.828 + if(ocrResponse & KMMCOCRAccessModeHCS)
1.829 + {
1.830 + CardArray().CardP(iCxCardCount)->iFlags |= KMMCardIsHighCapacity;
1.831 +#ifdef _DEBUG
1.832 + if(iCxCardType == ESDCardTypeIsSD)
1.833 + {
1.834 + __KTRACE_OPT(KPBUS1, Kern::Printf("Found large SD card."));
1.835 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM18, "Found large SD card" );
1.836 + }
1.837 + else if(iCxCardType == ESDCardTypeIsMMC)
1.838 + {
1.839 + __KTRACE_OPT(KPBUS1, Kern::Printf("Found large MMC card."));
1.840 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM19, "Found large MMC card" );
1.841 + }
1.842 +#endif
1.843 + }
1.844 + }
1.845 + }
1.846 +
1.847 + // Restore original settings
1.848 + iConfig.SetMode( EffectiveModes(s.iConfig) & KMMCModeEnableTimeOutRetry );
1.849 + iConfig.SetPollAttempts(KMMCMaxPollAttempts);
1.850 +
1.851 + // All cards are now ready and notified of the voltage range - ask ASSP to set it up
1.852 + if (iCxCardType==ESDCardTypeIsMMC)
1.853 + {
1.854 + iCurrentOpRange &= ~KMMCOCRAccessModeMask;
1.855 + }
1.856 + else
1.857 + {
1.858 + iCurrentOpRange &= ~KMMCOCRAccessModeHCS;
1.859 + }
1.860 +
1.861 + psu->SetVoltage(iCurrentOpRange);
1.862 + if (psu->SetState(EPsuOnFull) != KErrNone)
1.863 + {
1.864 + OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT3, this, (TInt) KMMCErrHardware );
1.865 + return KMMCErrHardware;
1.866 + }
1.867 +
1.868 + SMF_STATE(EStCIDCmd)
1.869 +
1.870 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM20, "EStCIDCmd" );
1.871 + s.FillCommandDesc(ECmdAllSendCID,0);
1.872 + m.ResetTraps();
1.873 + SMF_INVOKES(ExecCommandSMST,EStSendCIDIssued)
1.874 +
1.875 + SMF_STATE(EStSendCIDIssued)
1.876 +
1.877 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITIALISEMEMORYCARDSM21, "EStSendCIDIssued" );
1.878 + // All done - Higher level state machine expects CID in s.ResponseP()
1.879 +
1.880 + SMF_END
1.881 + }
1.882 +
1.883 +TMMCErr DSDStack::ConfigureMemoryCardSMST(TAny* aStackP)
1.884 + { return static_cast<DSDStack*>(aStackP)->ConfigureMemoryCardSM(); }
1.885 +
1.886 +TMMCErr DSDStack::ConfigureMemoryCardSM()
1.887 +/**
1.888 +*/
1.889 + {
1.890 + enum states
1.891 + {
1.892 + EStBegin=0,
1.893 + EStSendCSDDone,
1.894 + EStEnd
1.895 + };
1.896 +
1.897 + DMMCSession& s=Session();
1.898 + OstTrace1( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM, "Current session = 0x%x", &s );
1.899 +
1.900 + //coverity[UNREACHABLE]
1.901 + //Part of state machine design.
1.902 + SMF_BEGIN
1.903 +
1.904 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM1, "EStBegin" );
1.905 + // Cards is initialised so get its CSD
1.906 +
1.907 + s.FillCommandDesc(ECmdSendCSD, TUint32(CardArray().CardP(iCxCardCount)->iRCA) << 16);
1.908 + SMF_INVOKES(ExecCommandSMST, EStSendCSDDone)
1.909 +
1.910 + SMF_STATE(EStSendCSDDone)
1.911 +
1.912 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CONFIGUREMEMORYCARDSM2, "EStSendCSDDone" );
1.913 + // Store the CSD in the new card entry
1.914 + TMMCard* cardP = CardArray().CardP(iCxCardCount);
1.915 + cardP->iCSD = s.ResponseP();
1.916 +
1.917 + if(CardArray().Card(iCxCardCount).IsSDCard())
1.918 + {
1.919 + // Perform SD Specific parsing of the CSD structure
1.920 + if(cardP->CSD().CCC() & KMMCCmdClassLockCard)
1.921 + {
1.922 + cardP->iFlags |= KMMCardIsLockable;
1.923 + }
1.924 + }
1.925 + else
1.926 + {
1.927 + // Perform MMC Specific parsing of the CSD structure
1.928 + TUint specVers = cardP->CSD().SpecVers(); // 1 => 1.4, 2 => 2.0 - 2.2, 3 => 3.1
1.929 + if ((specVers >= 2) && (cardP->CSD().CCC() & KMMCCmdClassLockCard))
1.930 + {
1.931 + cardP->iFlags |= KMMCardIsLockable;
1.932 + }
1.933 + }
1.934 +
1.935 + // Check the state of the mechanical write protect switch
1.936 + if (WriteProtected(iCxCardCount))
1.937 + {
1.938 + cardP->iFlags |= KMMCardIsWriteProtected;
1.939 + }
1.940 +
1.941 + SMF_END
1.942 + }
1.943 +
1.944 +EXPORT_C TMMCErr DSDStack::InitStackAfterUnlockSM()
1.945 +//
1.946 +// Performs initialisation of the SD card after the card has been unlocked
1.947 +//
1.948 + {
1.949 + enum states
1.950 + {
1.951 + EStBegin=0,
1.952 + EStNextCard,
1.953 + EStSelectCard,
1.954 + EStSetBusWidth,
1.955 + EStSetBusWidth1,
1.956 + EStGetSDStatus,
1.957 + EStGetSDStatus1,
1.958 + EStDecodeSDStatus,
1.959 + EStDeselectCard,
1.960 + EStCardDeselectedReadCSD,
1.961 + EStCSDCmdSent,
1.962 + EStMoreCardsCheck,
1.963 + EStEnd
1.964 + };
1.965 +
1.966 + DMMCSession& s=Session();
1.967 + OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM, "Current session = 0x%x", &s );
1.968 +
1.969 + SMF_BEGIN
1.970 +
1.971 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM1, "EStBegin" );
1.972 + __KTRACE_OPT(KPBUS1, Kern::Printf(">DSDStack::InitStackAfterUnlockSM()"));
1.973 + iRCAPool.ReleaseUnlocked();
1.974 + iCxCardCount=0; // Reset current card number
1.975 +
1.976 + SMF_STATE(EStNextCard)
1.977 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM2, "EStNextCard" );
1.978 + AddressCard(iCxCardCount); // Address the next card
1.979 +
1.980 + if (!CardDetect(iCxCardCount))
1.981 + SMF_GOTOS(EStMoreCardsCheck)
1.982 +
1.983 + s.SetCard(CardArray().CardP(iCxCardCount));
1.984 +
1.985 + if (!CardArray().Card(iCxCardCount).IsSDCard())
1.986 + {
1.987 + SMF_INVOKES( DMMCStack::InitCurrentCardAfterUnlockSMST, EStMoreCardsCheck )
1.988 + }
1.989 +
1.990 + SMF_STATE(EStSelectCard)
1.991 +
1.992 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM3, "EStSelectCard" );
1.993 + TRCA targetRCA = CardArray().Card(iCxCardCount).RCA();
1.994 + if (targetRCA == SelectedCard())
1.995 + {
1.996 + SMF_GOTOS(EStSetBusWidth)
1.997 + }
1.998 +
1.999 + s.FillCommandDesc(ECmdSelectCard, targetRCA);
1.1000 + SMF_INVOKES(ExecCommandSMST,EStSetBusWidth)
1.1001 +
1.1002 + SMF_STATE(EStSetBusWidth)
1.1003 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM4, "EStSetBusWidth" );
1.1004 + const TMMCStatus status = s.LastStatus();
1.1005 + if((status & KMMCStatCardIsLocked) != 0)
1.1006 + SMF_GOTOS(EStDeselectCard)
1.1007 +
1.1008 + // set bus width with ACMD6
1.1009 + TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16;
1.1010 + s.FillCommandDesc(ECmdAppCmd, arg);
1.1011 + SMF_INVOKES(IssueCommandCheckResponseSMST,EStSetBusWidth1)
1.1012 +
1.1013 + SMF_STATE(EStSetBusWidth1)
1.1014 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM5, "EStSetBusWidth1" );
1.1015 + CardArray().Card(iCxCardCount).SetBusWidth(4);
1.1016 + DSDSession::FillAppCommandDesc(Command(), ESDACmdSetBusWidth, KSDBusWidth4);
1.1017 + SMF_INVOKES(IssueCommandCheckResponseSMST,EStGetSDStatus)
1.1018 +
1.1019 + SMF_STATE(EStGetSDStatus)
1.1020 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM6, "EStGetSDStatus" );
1.1021 + // Now we have sent ACMD6, ask the controller to set the bus width to 4
1.1022 + DoSetBusWidth(EBusWidth4);
1.1023 +
1.1024 + // get protected area size with ACMD13
1.1025 + TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16;
1.1026 + s.FillCommandDesc(ECmdAppCmd,arg);
1.1027 + SMF_INVOKES(IssueCommandCheckResponseSMST,EStGetSDStatus1)
1.1028 +
1.1029 + SMF_STATE(EStGetSDStatus1)
1.1030 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM7, "EStGetSDStatus1" );
1.1031 + DSDSession::FillAppCommandDesc(Command(), ESDACmdSDStatus);
1.1032 + s.FillCommandArgs(0, KSDStatusBlockLength, iPSLBuf, KSDStatusBlockLength);
1.1033 + SMF_INVOKES(IssueCommandCheckResponseSMST,EStDecodeSDStatus);
1.1034 +
1.1035 + SMF_STATE(EStDecodeSDStatus)
1.1036 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM8, "EStDecodeSDStatus" );
1.1037 +#ifdef _DEBUG
1.1038 + for (TUint i = 0; i < KSDStatusBlockLength; ++i)
1.1039 + {
1.1040 + __KTRACE_OPT(KPBUS1, Kern::Printf("SD_STATUS[0x%x] = %x", i, iPSLBuf[i]));
1.1041 + OstTraceExt2( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM9, "SD_STATUS[0x%x]=0x%x", i, (TUint) iPSLBuf[i]);
1.1042 + }
1.1043 +#endif
1.1044 + // bits 495:480 are SD_CARD_TYPE. Check this is 00xxh (x = don't care).
1.1045 +
1.1046 + if (iPSLBuf[2] != 0)
1.1047 + {
1.1048 + OstTraceFunctionExitExt( DSDSTACK_INITSTACKAFTERUNLOCKSM_EXIT, this, (TInt) KMMCErrNotSupported );
1.1049 + return KMMCErrNotSupported;
1.1050 + }
1.1051 +
1.1052 + // bits 479:448 contain SIZE_OF_PROTECTED_AREA.
1.1053 + // (This is bytes 4 to 7 in big-endian format.)
1.1054 +
1.1055 + TSDCard& sdc = CardArray().Card(iCxCardCount);
1.1056 + __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Card %d", iCxCardCount));
1.1057 + TUint32 size_of_protected_area = TMMC::BigEndian32(&iPSLBuf[4]);
1.1058 + __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: SizeOfProtectedArea: %d", size_of_protected_area));
1.1059 + OstTraceExt2( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM10, "iCxCardCount=%d;SizeOfProtectedArea=%d", iCxCardCount, (TInt) size_of_protected_area);
1.1060 + const TCSD& csd = sdc.CSD();
1.1061 + TUint32 pas = 0;
1.1062 +
1.1063 + if (sdc.IsHighCapacity())
1.1064 + {
1.1065 + // High Capacity Card
1.1066 + // Protected Area = SIZE_OF_PROTECTED_AREA
1.1067 + pas = size_of_protected_area;
1.1068 + __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack(SDHC): SetProtectedAreaSize: %d", pas));
1.1069 + OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM11, "SDHC: SetProtectedAreaSize=%d", pas);
1.1070 + }
1.1071 + else
1.1072 + {
1.1073 + // Standard Capacity Card
1.1074 + // Protected Area = SIZE_OF_PROTECTED_AREA * C_SIZE_MULT * BLOCK_LEN
1.1075 + pas = size_of_protected_area * (1 << (csd.CSizeMult() + 2 + csd.ReadBlLen()));
1.1076 + __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack(SDSC): SetProtectedAreaSize: %d", pas));
1.1077 + OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM12, "SDSC: SetProtectedAreaSize=%d", pas);
1.1078 + }
1.1079 +
1.1080 + sdc.SetProtectedAreaSize(pas);
1.1081 +
1.1082 + //bits 431:428 contain AU_SIZE
1.1083 + //(This is higher order 4 bits of 10th byte in big endian format)
1.1084 + TUint8 au = TUint8(iPSLBuf[10] >> 4);
1.1085 + if(au == 0) //AU_SIZE field in SD status register is undefined.
1.1086 + au = 6; //Defaulting to value corresponding to 512K
1.1087 + sdc.SetAUSize(au);
1.1088 +
1.1089 + SMF_INVOKES(SwitchToHighSpeedModeSMST, EStDeselectCard)
1.1090 +
1.1091 + SMF_STATE(EStDeselectCard)
1.1092 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM13, "EStDeselectCard" );
1.1093 + s.FillCommandDesc(ECmdSelectCard, 0);
1.1094 + SMF_INVOKES(ExecCommandSMST, EStCardDeselectedReadCSD)
1.1095 +
1.1096 + SMF_STATE(EStCardDeselectedReadCSD)
1.1097 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM14, "EStCardDeselectedReadCSD" );
1.1098 + //
1.1099 + // Read the card's CSD register (again)
1.1100 + //
1.1101 + // - We re-read the CSD, as the TRAN_SPEED field may have changed due to a switch to HS Mode
1.1102 + //
1.1103 + TUint32 arg = TUint32(CardArray().Card(iCxCardCount).RCA()) << 16;
1.1104 + s.FillCommandDesc( ECmdSendCSD, arg );
1.1105 + SMF_INVOKES(ExecCommandSMST, EStCSDCmdSent)
1.1106 +
1.1107 + SMF_STATE(EStCSDCmdSent)
1.1108 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM15, "EStCSDCmdSent" );
1.1109 + //
1.1110 + // Store the CSD in the card entry
1.1111 + //
1.1112 + TMMCard* cardP = iCardArray->CardP(iCxCardCount);
1.1113 + cardP->iCSD = s.ResponseP();
1.1114 +
1.1115 + SMF_STATE(EStMoreCardsCheck)
1.1116 + OstTrace0( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM16, "EStMoreCardsCheck" );
1.1117 + if (++iCxCardCount < (TInt)iMaxCardsInStack)
1.1118 + {
1.1119 + __KTRACE_OPT(KPBUS1, Kern::Printf("\t >DSDStack: Address Next card: %d",iCxCardCount));
1.1120 + OstTrace1( TRACE_INTERNALS, DSDSTACK_INITSTACKAFTERUNLOCKSM17, "Address Next card=%d", iCxCardCount);
1.1121 + SMF_GOTOS(EStNextCard)
1.1122 + }
1.1123 + else
1.1124 + {
1.1125 + AddressCard(KBroadcastToAllCards);
1.1126 + __KTRACE_OPT(KPBUS1, Kern::Printf("<DSDStack::InitStackAfterUnlockSM()"));
1.1127 + }
1.1128 +
1.1129 + SMF_END
1.1130 +
1.1131 + }
1.1132 +
1.1133 +TMMCErr DSDStack::CIMReadWriteMemoryBlocksSMST(TAny* aStackP)
1.1134 + { return( static_cast<DSDStack *>(aStackP)->DMMCStack::CIMReadWriteBlocksSM() ); }
1.1135 +
1.1136 +
1.1137 +EXPORT_C TMMCErr DSDStack::CIMReadWriteBlocksSM()
1.1138 +//
1.1139 +// This macro performs single/multiple block reads and writes
1.1140 +// For normal read/write block operations, this function determines the appropriate
1.1141 +// MMC command to send and fills the command descriptor accordingly based on
1.1142 +// the value of the session ID set. However, it is necessary to have set the
1.1143 +// command arguments (with DMMCSession::FillCommandArgs()) before this function
1.1144 +// is called.
1.1145 +// For special block read/write operations, e.g. lock/unlock, it is required to
1.1146 +// have already filled the command descriptor (with DMMCSession::FillCommandDesc())
1.1147 +// for the special command required - in addition to have setup the command arguments.
1.1148 +//
1.1149 + {
1.1150 + enum states
1.1151 + {
1.1152 + EStBegin=0,
1.1153 + EStRestart,
1.1154 + EStAttached,
1.1155 + EStLength1,
1.1156 + EStLengthSet,
1.1157 + EStIssued,
1.1158 + EStWaitFinish,
1.1159 + EStWaitFinish1,
1.1160 + EStRWFinish,
1.1161 + EStDone,
1.1162 + EStEnd
1.1163 + };
1.1164 +
1.1165 + DMMCSession& s = Session();
1.1166 + OstTrace1( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM, "Current session = 0x%x", &s );
1.1167 +
1.1168 + __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:RWBlocksSM %x",TUint(s.iLastStatus)));
1.1169 +
1.1170 + SMF_BEGIN
1.1171 +
1.1172 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM1, "EStBegin" );
1.1173 + TSDCard& sdCard = *static_cast<TSDCard*>(s.iCardP);
1.1174 + AddressCard(sdCard.iIndex-1);
1.1175 +
1.1176 + if(sdCard.IsSDCard() == EFalse)
1.1177 + {
1.1178 + //
1.1179 + // If this is not an SD card, then use the more appropriate
1.1180 + // MMC state machine as this is optimised for MMC performance
1.1181 + //
1.1182 + SMF_INVOKES(CIMReadWriteMemoryBlocksSMST, EStDone);
1.1183 + }
1.1184 +
1.1185 + if(s.iSessionID == ECIMWriteBlock || s.iSessionID == ECIMWriteMBlock)
1.1186 + {
1.1187 + // Check that the card supports class 4 (Write) commands
1.1188 + const TUint ccc = s.iCardP->CSD().CCC();
1.1189 + if(!(ccc & KMMCCmdClassBlockWrite))
1.1190 + {
1.1191 + OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT, this, (TInt) KMMCErrNotSupported );
1.1192 + return KMMCErrNotSupported;
1.1193 + }
1.1194 + }
1.1195 +
1.1196 + Command().iCustomRetries = 0; // MBW retries
1.1197 + s.iState |= KMMCSessStateInProgress;
1.1198 + m.SetTraps(KMMCErrInitContext);
1.1199 +
1.1200 + SMF_STATE(EStRestart) // NB: ErrBypass is not processed here
1.1201 +
1.1202 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM2, "EStRestart" );
1.1203 + SMF_CALLMEWR(EStRestart) // Create a recursive call entry to recover from the errors trapped
1.1204 + m.SetTraps(KMMCErrStatus);
1.1205 + if (s.Command().iSpec.iCommandClass!=KMMCCmdClassApplication || s.Command().iCommand==ECmdAppCmd )
1.1206 + {
1.1207 + s.ResetCommandStack();
1.1208 + SMF_INVOKES( AttachCardSMST, EStAttached ) // attachment is mandatory here
1.1209 + }
1.1210 +
1.1211 + SMF_BPOINT(EStAttached)
1.1212 +
1.1213 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM3, "EStAttached" );
1.1214 + TMMCCommandDesc& cmd = s.Command();
1.1215 +
1.1216 + const TUint32 blockLength = cmd.BlockLength();
1.1217 + if((blockLength == 0) || (blockLength > (TUint)KDefaultBlockLenInBytes))
1.1218 + {
1.1219 + __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:RWBlocksSM err BlockLen:%d",blockLength));
1.1220 + OstTrace1( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM4, "blockLength=%d", blockLength );
1.1221 + OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT1, this, (TInt) KMMCErrArgument );
1.1222 + return KMMCErrArgument;
1.1223 + }
1.1224 +
1.1225 + if(s.iSessionID == ECIMReadBlock ||
1.1226 + s.iSessionID == ECIMWriteBlock ||
1.1227 + s.iSessionID == ECIMReadMBlock ||
1.1228 + s.iSessionID == ECIMWriteMBlock)
1.1229 + {
1.1230 + // read/write operation
1.1231 + if(!cmd.AdjustForBlockOrByteAccess(s))
1.1232 + {
1.1233 + // unable to convert command arguments to suit the underlying block/byte access mode
1.1234 + OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT2, this, (TInt) KMMCErrArgument );
1.1235 + return KMMCErrArgument;
1.1236 + }
1.1237 + }
1.1238 +
1.1239 + // Set the block length if it has changed. Always set for ECIMLockUnlock.
1.1240 + if ((blockLength == s.iCardP->iSetBlockLen) && (s.iSessionID != ECIMLockUnlock))
1.1241 + {
1.1242 + SMF_GOTOS( EStLengthSet )
1.1243 + }
1.1244 +
1.1245 + s.iCardP->iSetBlockLen = 0;
1.1246 + s.PushCommandStack();
1.1247 + s.FillCommandDesc( ECmdSetBlockLen, blockLength );
1.1248 + SMF_INVOKES( ExecCommandSMST, EStLength1 )
1.1249 +
1.1250 + SMF_STATE(EStLength1)
1.1251 +
1.1252 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM5, "EStLength1" );
1.1253 + const TMMCStatus status(s.ResponseP());
1.1254 + s.PopCommandStack();
1.1255 + if (status.Error())
1.1256 + {
1.1257 + OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT3, this, (TInt) KMMCErrStatus );
1.1258 + SMF_RETURN(KMMCErrStatus)
1.1259 + }
1.1260 + s.iCardP->iSetBlockLen = s.Command().BlockLength();
1.1261 +
1.1262 + SMF_STATE(EStLengthSet)
1.1263 +
1.1264 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM6, "EStLengthSet" );
1.1265 + TMMCCommandDesc& cmd = s.Command();
1.1266 + TUint opType = 0;
1.1267 + const TUint kTypeWrite = KBit0;
1.1268 + const TUint kTypeMultiple = KBit1;
1.1269 + const TUint kTypeSpecial = KBit2;
1.1270 + static const TMMCCommandEnum cmdCodes[4] =
1.1271 + {ECmdReadSingleBlock, ECmdWriteBlock, ECmdReadMultipleBlock, ECmdWriteMultipleBlock};
1.1272 +
1.1273 + switch( s.iSessionID )
1.1274 + {
1.1275 + case ECIMReadBlock:
1.1276 + break;
1.1277 + case ECIMWriteBlock:
1.1278 + opType=kTypeWrite;
1.1279 + break;
1.1280 + case ECIMReadMBlock:
1.1281 + opType=kTypeMultiple;
1.1282 + break;
1.1283 + case ECIMWriteMBlock:
1.1284 + opType=kTypeWrite|kTypeMultiple;
1.1285 + break;
1.1286 + case ECIMLockUnlock:
1.1287 + default:
1.1288 + opType=kTypeSpecial;
1.1289 + break;
1.1290 + }
1.1291 +
1.1292 + const TUint blocks = cmd.iTotalLength / cmd.BlockLength();
1.1293 + if ( blocks * cmd.BlockLength() != cmd.iTotalLength )
1.1294 + {
1.1295 + OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT4, this, (TInt) KMMCErrArgument );
1.1296 + return KMMCErrArgument;
1.1297 + }
1.1298 +
1.1299 + if ( !(opType & kTypeSpecial) ) // A special session has already set its command descriptor
1.1300 + {
1.1301 + if (blocks==1)
1.1302 + opType &= ~kTypeMultiple;
1.1303 +
1.1304 + TUint32 oldFlags = cmd.iFlags; // Store the existing command flags, as they will be reset by FillCommandDesc()
1.1305 + cmd.iCommand = cmdCodes[opType];
1.1306 + s.FillCommandDesc();
1.1307 + cmd.iFlags = oldFlags; // ...and restore the old command flags
1.1308 + }
1.1309 +
1.1310 + // NB We need to trap KMMCErrStatus errors, because if one occurs,
1.1311 + // we still need to wait to exit PRG/RCV/DATA state
1.1312 + if (Command().iCommand == ECmdWriteMultipleBlock)
1.1313 + {
1.1314 + Command().iExecNotHandle = KMMCErrDataCRC | KMMCErrDataTimeOut;
1.1315 + m.SetTraps(KMMCErrStatus | KMMCErrDataCRC | KMMCErrDataTimeOut);
1.1316 + }
1.1317 + else
1.1318 + {
1.1319 + m.SetTraps(KMMCErrStatus);
1.1320 + }
1.1321 +
1.1322 + SMF_INVOKES( ExecCommandSMST, EStIssued )
1.1323 +
1.1324 + SMF_STATE(EStIssued)
1.1325 +
1.1326 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM7, "EStIssued" );
1.1327 + // check state of card after data transfer with CMD13.
1.1328 + if (s.Command().Direction() != 0)
1.1329 + {
1.1330 + SMF_GOTOS(EStWaitFinish)
1.1331 + }
1.1332 +
1.1333 + SMF_GOTOS(EStRWFinish);
1.1334 +
1.1335 + SMF_STATE(EStWaitFinish)
1.1336 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM8, "EStWaitFinish" );
1.1337 + // if MBW fail, then recover by rewriting ALL blocks...
1.1338 + // (used to recover using ACMD22, but this has been changed
1.1339 + // as is difficult to test for little gain in efficiency)
1.1340 + if (Command().iCommand == ECmdWriteMultipleBlock && err != 0)
1.1341 + {
1.1342 + if (Command().iCustomRetries++ >= (TInt) KSDMaxMBWRetries)
1.1343 + {
1.1344 + OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT5, this, (TInt) err );
1.1345 + SMF_RETURN(err)
1.1346 + }
1.1347 +
1.1348 + m.Pop(); // remove recursive call to EStRestart
1.1349 + SMF_GOTOS(EStRestart)
1.1350 + }
1.1351 +
1.1352 + // Save the status and examine it after issuing CMD13...
1.1353 + // NB We don't know where in the command stack the last response is stored (e.g. there may
1.1354 + // have bee a Deselect/Select issued), but we do know last response is stored in iLastStatus
1.1355 + TMMC::BigEndian4Bytes(s.ResponseP(), s.iLastStatus);
1.1356 +
1.1357 + // ...else issue CMD13 to poll for the card finishing and check for errors
1.1358 + s.PushCommandStack();
1.1359 + s.FillCommandDesc(ECmdSendStatus, 0);
1.1360 + SMF_INVOKES(ExecCommandSMST, EStWaitFinish1)
1.1361 +
1.1362 + SMF_STATE(EStWaitFinish1)
1.1363 +
1.1364 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM9, "EStWaitFinish1" );
1.1365 + const TMMCStatus status(s.ResponseP());
1.1366 + s.PopCommandStack();
1.1367 +
1.1368 +#ifdef __WINS__
1.1369 + SMF_GOTOS(EStRWFinish);
1.1370 +#else
1.1371 + const TMMCardStateEnum st1 = status.State();
1.1372 +
1.1373 + if (st1 == ECardStatePrg || st1 == ECardStateRcv || st1 == ECardStateData)
1.1374 + {
1.1375 + SMF_INVOKES(ProgramTimerSMST, EStWaitFinish);
1.1376 + }
1.1377 +
1.1378 + if (status.Error())
1.1379 + {
1.1380 + OstTraceFunctionExitExt( DUP7_DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT, this, (TInt) KMMCErrStatus );
1.1381 + SMF_RETURN(KMMCErrStatus)
1.1382 + }
1.1383 +#endif
1.1384 +
1.1385 + // Fall through if CURRENT_STATE is not PGM or DATA
1.1386 + SMF_STATE(EStRWFinish)
1.1387 +
1.1388 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM10, "EStRWFinish" );
1.1389 + if (TMMCStatus(s.ResponseP()).Error() != 0)
1.1390 + {
1.1391 + OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT6, this, (TInt) KMMCErrStatus );
1.1392 + SMF_RETURN(KMMCErrStatus);
1.1393 + }
1.1394 +
1.1395 + s.iState &= ~KMMCSessStateInProgress;
1.1396 +
1.1397 + // skip over recursive entry or throw error and catch in CIMLockUnlockSM()
1.1398 + TMMCErr ret = (s.Command().iCommand == ECmdLockUnlock) ? KMMCErrUpdPswd : KMMCErrBypass;
1.1399 + OstTraceFunctionExitExt( DSDSTACK_CIMREADWRITEBLOCKSSM_EXIT7, this, (TInt) ret );
1.1400 + return ret;
1.1401 +
1.1402 + SMF_STATE(EStDone)
1.1403 +
1.1404 + OstTrace0( TRACE_INTERNALS, DSDSTACK_CIMREADWRITEBLOCKSSM11, "EStDone" );
1.1405 + __KTRACE_OPT(KPBUS1,Kern::Printf("<SD:RWBlocksSM()"));
1.1406 +
1.1407 + SMF_END
1.1408 + }
1.1409 +
1.1410 +EXPORT_C TMMCErr DSDStack::ModifyCardCapabilitySM()
1.1411 +//
1.1412 +// This function provides a chance to modify the capability of paticular cards.
1.1413 +// Licensee may overide this function to modify certain card's capability as needed.
1.1414 +// A state machine is needed in derived function and function of base class should be
1.1415 +// called in order to act more generic behaviour.
1.1416 +//
1.1417 + {
1.1418 + enum states
1.1419 + {
1.1420 + EStBegin=0,
1.1421 + EStDone,
1.1422 + EStEnd
1.1423 + };
1.1424 +
1.1425 + //coverity[unreachable]
1.1426 + //Part of state machine design.
1.1427 + SMF_BEGIN
1.1428 +
1.1429 + OstTrace0( TRACE_INTERNALS, DSDSTACK_MODIFYCARDCAPABILITYSM, "EStBegin" );
1.1430 + SMF_INVOKES( DMMCStack::BaseModifyCardCapabilitySMST, EStDone )
1.1431 +
1.1432 + SMF_STATE(EStDone)
1.1433 +
1.1434 + OstTrace0( TRACE_INTERNALS, DSDSTACK_MODIFYCARDCAPABILITYSM1, "EStDone" );
1.1435 +
1.1436 + SMF_END
1.1437 + }
1.1438 +
1.1439 +inline TMMCErr DSDStack::SwitchToHighSpeedModeSMST( TAny* aStackP )
1.1440 + { return( static_cast<DSDStack *>(aStackP)->DSDStack::SwitchToHighSpeedModeSM() ); }
1.1441 +
1.1442 +TMMCErr DSDStack::SwitchToHighSpeedModeSM()
1.1443 + {
1.1444 + enum states
1.1445 + {
1.1446 + EStBegin=0,
1.1447 + EstCheckController,
1.1448 + EStSendSCRCmd,
1.1449 + EStCheckSpecVer,
1.1450 + EStCheckFunction,
1.1451 + EStCheckFunctionSent,
1.1452 + EStSwitchFunctionSent,
1.1453 + EStDone,
1.1454 + EStEnd
1.1455 + };
1.1456 +
1.1457 + __KTRACE_OPT(KPBUS1,Kern::Printf(">SD:SwitchToHighSpeedModeSM "));
1.1458 +
1.1459 + DMMCSession& s = Session();
1.1460 + OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM, "Current session = 0x%x", &s );
1.1461 +
1.1462 + SMF_BEGIN
1.1463 +
1.1464 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM1, "EStBegin");
1.1465 +
1.1466 + SMF_STATE(EstCheckController)
1.1467 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM2, "EstCheckController");
1.1468 + // Get the clock speed supported by the controller
1.1469 + TMMCMachineInfoV4 machineInfo;
1.1470 + TMMCMachineInfoV4Pckg machineInfoPckg(machineInfo);
1.1471 + MachineInfo(machineInfoPckg);
1.1472 +
1.1473 + if (machineInfo.iVersion >= TMMCMachineInfoV4::EVersion4)
1.1474 + {
1.1475 + if (machineInfo.iMaxClockSpeedInMhz < (KSDDTClk50MHz/1000) )
1.1476 + {
1.1477 + __KTRACE_OPT(KPBUS1, Kern::Printf("High speed mode not supported by controller"));
1.1478 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM3, "High speed mode not supported by controller");
1.1479 + SMF_GOTOS(EStDone);
1.1480 + }
1.1481 + }
1.1482 +
1.1483 + SMF_STATE(EStSendSCRCmd)
1.1484 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM4, "EStSendSCRCmd");
1.1485 + //
1.1486 + // ACMD51 Read the SD Configuration Register
1.1487 + //
1.1488 + DSDSession::FillAppCommandDesc(Command(), ESDACmdSendSCR);
1.1489 + s.FillCommandArgs(0, KSDSCRLength, iPSLBuf, KSDSCRLength);
1.1490 + SMF_INVOKES(ExecCommandSMST, EStCheckSpecVer);
1.1491 +
1.1492 + SMF_STATE(EStCheckSpecVer)
1.1493 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM5, "EStCheckSpecVer");
1.1494 + //
1.1495 + // Check the SD version
1.1496 + //
1.1497 + // 0 : version 1.0-1.01 : SDHS Is NOT Supported
1.1498 + // 1 : version 1.10+ : SDHS Is Supported
1.1499 + //
1.1500 + __KTRACE_OPT(KPBUS1,Kern::Printf(" SD Configuration Register received"));
1.1501 + __KTRACE_OPT(KPBUS1,Kern::Printf(" ...card_status=%x", TUint(s.iLastStatus)));
1.1502 + OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM6, "SD Configuration Register received: card_status=0x%x", (TUint) s.iLastStatus);
1.1503 +
1.1504 +#ifdef _DEBUG
1.1505 + for (TUint32 i = 0; i < KSDSCRLength; ++i)
1.1506 + {
1.1507 + __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SCR_STATUS[0x%x] = %x", i, iPSLBuf[i]));
1.1508 + }
1.1509 +#endif
1.1510 +
1.1511 + if(iPSLBuf[0]==2)
1.1512 + {
1.1513 + __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 2"));
1.1514 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM7, "SD Spec Version 2");
1.1515 + SMF_GOTOS(EStCheckFunction);
1.1516 + }
1.1517 +
1.1518 + if(iPSLBuf[0]==1)
1.1519 + {
1.1520 + __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 1.10"));
1.1521 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM8, "SD Spec Version 1.10");
1.1522 + SMF_GOTOS(EStCheckFunction);
1.1523 + }
1.1524 +
1.1525 + if(iPSLBuf[0]==0)
1.1526 + {
1.1527 + __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version 1.01"));
1.1528 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM9, "SD Spec Version 1.01");
1.1529 + SMF_GOTOS(EStDone);
1.1530 + }
1.1531 +
1.1532 + __KTRACE_OPT(KPBUS1,Kern::Printf(" ...SD Spec Version > 2 !"));
1.1533 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM10, "SD Spec Version > 2");
1.1534 +
1.1535 + SMF_STATE(EStCheckFunction)
1.1536 +
1.1537 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM11, "EStCheckFunction");
1.1538 + m.SetTraps(KMMCErrResponseTimeOut | KMMCErrNotSupported);
1.1539 +
1.1540 + //
1.1541 + // SD1.1 uses CMD6 which is not defined by the MMCA
1.1542 + // - fill in command details using the SD Specific command description table
1.1543 + //
1.1544 +
1.1545 + DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSwitchFunction);
1.1546 + s.FillCommandArgs(KSDCheckFunctionHighSpeed, KSDSwitchFuncLength, iPSLBuf, KSDSwitchFuncLength);
1.1547 +
1.1548 + SMF_INVOKES(IssueCommandCheckResponseSMST,EStCheckFunctionSent)
1.1549 +
1.1550 + SMF_STATE(EStCheckFunctionSent)
1.1551 +
1.1552 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM12, "EStCheckFunctionSent");
1.1553 + __KTRACE_OPT(KPBUS1,Kern::Printf(" CheckFunctionSent %x",TUint(s.iLastStatus)));
1.1554 + OstTrace1( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM13, "CheckFunctionSent=0x%x", (TUint) s.iLastStatus);
1.1555 +
1.1556 + m.ResetTraps();
1.1557 +
1.1558 + if(err == KMMCErrResponseTimeOut)
1.1559 + {
1.1560 + __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Read] Response Timeout"));
1.1561 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM14, "CMD6 [Read] Response Timeout");
1.1562 + SMF_GOTOS(EStDone);
1.1563 + }
1.1564 + else if(err == KMMCErrNotSupported)
1.1565 + {
1.1566 + __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Read] Not Supported"));
1.1567 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM15, "CMD6 [Read] Not Supported");
1.1568 + SMF_GOTOS(EStDone);
1.1569 + }
1.1570 +
1.1571 +#ifdef _DEBUG
1.1572 + for (TUint32 i = 0; i < KSDSwitchFuncLength; ++i)
1.1573 + {
1.1574 + __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SD Switch Func Status[0x%x] = %x", i, iPSLBuf[i]));
1.1575 + }
1.1576 +
1.1577 + m.SetTraps(KMMCErrResponseTimeOut);
1.1578 +#endif
1.1579 +
1.1580 + //
1.1581 + // SD1.1 uses CMD6 which is not defined by the MMCA
1.1582 + // - fill in command details using the SD Specific command description table
1.1583 + //
1.1584 +
1.1585 + DSDSession::FillSdSpecificCommandDesc(Command(), ESDCmdSwitchFunction);
1.1586 + s.FillCommandArgs(KSDSwitchFunctionHighSpeed, KSDSwitchFuncLength, iPSLBuf, KSDSwitchFuncLength);
1.1587 +
1.1588 + SMF_INVOKES(IssueCommandCheckResponseSMST,EStSwitchFunctionSent)
1.1589 +
1.1590 + SMF_STATE(EStSwitchFunctionSent)
1.1591 +
1.1592 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM16, "EStSwitchFunctionSent");
1.1593 +#ifdef _DEBUG
1.1594 + m.ResetTraps();
1.1595 +
1.1596 + if(err == KMMCErrResponseTimeOut)
1.1597 + {
1.1598 + __KTRACE_OPT(KPBUS1,Kern::Printf(" ...CMD6 [Write] Response Timeout"));
1.1599 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM17, "CMD6 [Write] Response Timeout");
1.1600 + }
1.1601 +
1.1602 + for (TUint32 i = 0; i < KSDSwitchFuncLength; ++i)
1.1603 + {
1.1604 + __KTRACE_OPT(KPBUS1, Kern::Printf(" ...SD Switch[0x%x] = %x", i, iPSLBuf[i]));
1.1605 + OstTraceExt2( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM18, "SD Switch[0x%x]=0x%x", (TUint) i, (TUint) iPSLBuf[i]);
1.1606 + }
1.1607 +#endif
1.1608 +
1.1609 + SMF_STATE(EStDone)
1.1610 +
1.1611 + OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM19, "EStSwitchFunctionSent");
1.1612 +
1.1613 + SMF_END
1.1614 + }
1.1615 +
1.1616 +
1.1617 +EXPORT_C DMMCSession* DSDStack::AllocSession(const TMMCCallBack& aCallBack) const
1.1618 +/**
1.1619 +* Factory function to create DMMCSession derived object. Non-generic MMC
1.1620 +* controllers can override this to generate more specific objects.
1.1621 +* @param aCallBack Callback function to notify the client that a session has completed
1.1622 +* @return A pointer to the new session
1.1623 +*/
1.1624 + {
1.1625 + OstTraceFunctionEntry1( DSDSTACK_ALLOCSESSION_ENTRY, this );
1.1626 + return new DSDSession(aCallBack);
1.1627 + }
1.1628 +
1.1629 +EXPORT_C void DSDStack::Dummy1() {}
1.1630 +EXPORT_C void DSDStack::Dummy2() {}
1.1631 +EXPORT_C void DSDStack::Dummy3() {}
1.1632 +EXPORT_C void DSDStack::Dummy4() {}