1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/boardsupport/emulator/emulatorbsp/specific/mmc.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1444 @@
1.4 +// Copyright (c) 2000-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 "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 +// PP_MMC.CPP
1.18 +//
1.19 +//
1.20 +
1.21 +#include "plat_priv.h"
1.22 +#include <property.h>
1.23 +#include "variant.h"
1.24 +#include "variantmediadef.h"
1.25 +#include "mmci.h"
1.26 +
1.27 +//#define __CARD0_NOT_LOCKABLE__
1.28 +//#define __CARD1_NOT_LOCKABLE__
1.29 +
1.30 +const TInt KDiskSectorSize=512;
1.31 +
1.32 +TInt DWinsMMCStack::TotalMDiskSize=0; ///< mmc card size for emulator
1.33 +TUint DWinsMMCStack::CSIZE=0; ///< mmc card size field
1.34 +TUint DWinsMMCStack::CSIZE_MULT=0; ///< mmc card size field
1.35 +
1.36 +TInt DWinsMMCStack::TotalWinsMMC_CardSlots = KDefault_TotalWinsCardSlots; ///< total number of MMC card slots for the emulator
1.37 +TInt DWinsMMCStack::TotalWinsMMC_Cards = KDefault_TotalWinsCards; ///< total number of MMC cards for the emulator
1.38 +
1.39 +
1.40 +const TUint32 KCsdStructure = 0x01; /* CSD Version No 1.1 */
1.41 +const TUint32 KCsdSpecVers = 0x03; /* Version 3.1 */
1.42 +
1.43 +TInt MapLastErrorEpoc()
1.44 +//
1.45 +// Map an NT error to an Epoc/32 error.
1.46 +//
1.47 + {
1.48 + TInt res=KErrGeneral;
1.49 + switch (GetLastError())
1.50 + {
1.51 + case ERROR_SHARING_VIOLATION : res=KErrAccessDenied; break;
1.52 + case ERROR_LOCK_VIOLATION : res=KErrLocked; break;
1.53 + case ERROR_FILE_NOT_FOUND: res=KErrNotFound; break;
1.54 + case ERROR_PATH_NOT_FOUND: res=KErrPathNotFound; break;
1.55 + case ERROR_ALREADY_EXISTS:
1.56 + case ERROR_FILE_EXISTS:
1.57 + res=KErrAlreadyExists;
1.58 + break;
1.59 + case ERROR_NOT_READY: res=KErrNotReady; break;
1.60 + case ERROR_UNRECOGNIZED_VOLUME:
1.61 + case ERROR_NOT_DOS_DISK:
1.62 + res=KErrUnknown;
1.63 + break;
1.64 + case ERROR_UNRECOGNIZED_MEDIA: res=KErrCorrupt; break;
1.65 + case ERROR_INVALID_NAME: res=KErrBadName; break;
1.66 + case ERROR_NO_MORE_FILES: res=KErrEof; break;
1.67 + }
1.68 + return(res);
1.69 + }
1.70 +
1.71 +TMMCErr MapLastErrorMmc()
1.72 +//
1.73 +// Map an NT error to a TMMCErr error.
1.74 +//
1.75 + {
1.76 + DWORD r=GetLastError();
1.77 + TInt res=KErrGeneral;
1.78 + switch (r)
1.79 + {
1.80 + case ERROR_SHARING_VIOLATION:
1.81 + case ERROR_LOCK_VIOLATION:
1.82 + res=KMMCErrLocked; // KErrLocked
1.83 + break;
1.84 + case ERROR_FILE_NOT_FOUND:
1.85 + case ERROR_PATH_NOT_FOUND:
1.86 + res=KMMCErrNotFound; // KErrNotFound
1.87 + break;
1.88 + case ERROR_ALREADY_EXISTS:
1.89 + case ERROR_FILE_EXISTS:
1.90 + res=KMMCErrAlreadyExists; // KErrAlreadyExists
1.91 + break;
1.92 + case ERROR_NOT_READY: res=KMMCErrNoCard; break;
1.93 + case ERROR_UNRECOGNIZED_VOLUME:
1.94 + case ERROR_NOT_DOS_DISK:
1.95 + res=KMMCErrGeneral; // KErrGeneral
1.96 + break;
1.97 + case ERROR_UNRECOGNIZED_MEDIA:
1.98 + case ERROR_INVALID_NAME:
1.99 + case ERROR_NO_MORE_FILES:
1.100 + res=KMMCErrResponseCRC; // KErrCorrupt
1.101 + break;
1.102 + }
1.103 + return(res);
1.104 + }
1.105 +
1.106 +
1.107 +void DWinsMMCStack::MachineInfo(TMMCMachineInfo& aMachineInfo)
1.108 +//
1.109 +// Return machine info relating to this MultiMediaCard Stack
1.110 +//
1.111 + {
1.112 + aMachineInfo.iTotalSockets=TotalWinsMMC_CardSlots;
1.113 + aMachineInfo.iTotalMediaChanges=0; // Not used at present
1.114 + aMachineInfo.iTotalPrimarySupplies=0; // Not used at present
1.115 +
1.116 + aMachineInfo.iFlags = TMMCMachineInfo::ESupportsDoubleBuffering;
1.117 + aMachineInfo.iBaseBusNumber=0;
1.118 +
1.119 + __KTRACE_OPT(KPBUS1,Kern::Printf("<WinsMMC:MachineInfo"));
1.120 + __KTRACE_OPT(KPBUS1,Kern::Printf(" %d stacks",aMachineInfo.iTotalSockets));
1.121 +
1.122 + __ASSERT_DEBUG(aMachineInfo.iTotalSockets<=KMaxMMCardsPerStack,Panic(EWinsMMCBadMachineInfo));
1.123 + }
1.124 +
1.125 +void DWinsMMCStack::AdjustPartialRead(
1.126 + const TMMCard* aCard, TUint32 aStart,
1.127 +#ifdef _DEBUG
1.128 + TUint32 aEnd,
1.129 +#else
1.130 + TUint32 /*aEnd*/,
1.131 +#endif
1.132 + TUint32* aPhysStart, TUint32* aPhysEnd) const
1.133 + {
1.134 + const TUint32 blkLen = 1 << aCard->MaxReadBlLen();
1.135 + const TUint32 blkMsk = blkLen - 1;
1.136 +#ifdef _DEBUG
1.137 + __ASSERT_DEBUG(aCard->CSD().ReadBlPartial(), Panic(EWinsMMCAPRNotSupp));
1.138 + __ASSERT_DEBUG(aEnd - aStart <= blkLen, Panic(EWinsMMCAPRRange));
1.139 + __ASSERT_DEBUG((aEnd & ~blkMsk) > (aStart & ~blkMsk), Panic(EWinsMMCAPRBoundary));
1.140 +#endif
1.141 +
1.142 + *aPhysStart = aStart & ~blkMsk;
1.143 + *aPhysEnd = *aPhysStart + blkLen;
1.144 + }
1.145 +
1.146 +void DWinsMMCStack::GetBufferInfo(TUint8** aMDBuf, TInt* aMDBufLen)
1.147 + {
1.148 + *aMDBuf = iMDBuf;
1.149 + *aMDBufLen = iMDBufLen;
1.150 + }
1.151 +
1.152 +void DWinsMMCStack::Panic(TWinsMMCPanic aPanic)
1.153 + {
1.154 + _LIT(KPncNm,"PBUS-MMC-WINS");
1.155 + Kern::PanicCurrentThread(KPncNm,aPanic);
1.156 + }
1.157 +
1.158 +DWinsMMCStack::DWinsMMCStack(TInt aBus, DMMCSocket* aSocket)
1.159 + :DMMCStack(aBus, aSocket)
1.160 + {
1.161 +
1.162 +// iAddressedCard=0;
1.163 +// iSecureArgDevAddr=0;
1.164 +// iSecureArgTotalLength=0;
1.165 +// iCMD42Failed=EFalse;
1.166 + }
1.167 +
1.168 +
1.169 +/**
1.170 + Allocate cards. Only called at bootup, so no cleanup if fails.
1.171 +*/
1.172 +TInt DWinsMMCStack::Init()
1.173 + {
1.174 +
1.175 + //-- try to read number of mmc cards and slots from epoc.ini file
1.176 + const TInt MmcSlots = Property::GetInt("MultiMediaCardSlots");
1.177 + const TInt MmcCards = Property::GetInt("MultiMediaCardsNum");
1.178 +
1.179 + if(MmcSlots == 0 && MmcCards == 0)
1.180 + {//-- parameters not specified, do nothing; static variables are initialized with default values
1.181 + }
1.182 + else
1.183 + {
1.184 + if((MmcSlots == 0 && MmcCards >0) || (MmcSlots > 0 && MmcCards ==0))
1.185 + {//-- only one of the parameters is specified. use it as "Cards quantity"
1.186 + TotalWinsMMC_Cards = Max(MmcSlots, MmcCards); //-- chose non zero value
1.187 + TotalWinsMMC_CardSlots = Max(1, TotalWinsMMC_Cards-1);
1.188 + }
1.189 + else
1.190 + {//-- both parameters are specified
1.191 + TotalWinsMMC_Cards = MmcCards;
1.192 + TotalWinsMMC_CardSlots = MmcSlots;
1.193 + }
1.194 +
1.195 + }//if(!MmcSlots && !MmcCards)
1.196 +
1.197 + TotalWinsMMC_Cards = Min(TotalWinsMMC_Cards, KMax_TotalWinsCards);
1.198 + TotalWinsMMC_CardSlots = Min(TotalWinsMMC_CardSlots, KMax_TotalWinsCardSlots);
1.199 +
1.200 +
1.201 + if((iCardArray = new TMMCardArray(this)) == NULL)
1.202 + return KErrNoMemory;
1.203 +
1.204 + TInt r=DMMCStack::Init();
1.205 + if(r!=KErrNone)
1.206 + return r;
1.207 +
1.208 + DMediaChangeBase* pMCBase = MMCSocket()->iMediaChange;
1.209 + static_cast<DWinsMMCMediaChange*>(pMCBase)->SetStackP(this);
1.210 + Wins::SetMediaChangeCallBackPtr(DWinsMMCMediaChange::MediaChangeCallBack, (TAny*)pMCBase);
1.211 +
1.212 + //
1.213 + // Over time memory can become fragmented, and so it is not possible to
1.214 + // allocate physically contiguous pages. Therefore, the buffers for IO
1.215 + // are allocated at startup.
1.216 + //
1.217 + // For the WINS implementation, fragmentation does not matter because
1.218 + // DMA is not used. The memory must still be allocated here so MEDMMC is
1.219 + // able to use it.
1.220 + //
1.221 + // The constant calculations could be folded, but this illustrates how the
1.222 + // values are derived.
1.223 + //
1.224 +
1.225 + // MMC only - values from Hitachi 16Mb card, datasheet HB288016MM1
1.226 +
1.227 + // minor buffer must contain enough space for MBR or block
1.228 + const TUint mmcBlkSzLog2 = 9; // READ_BLK_LEN and WRITE_BLK_LEN
1.229 + const TUint mmcBlkSz = 1 << mmcBlkSzLog2;
1.230 + const TInt mmcMinorBufLen = Max(KDiskSectorSize, mmcBlkSz);
1.231 +
1.232 + // There are 2 slots each with up to 2 media drivers; we allocate 8 blocks for each driver.
1.233 + // It is the media drivers' responsibility to devide up the buffer space according
1.234 + // to which slot number is allocated to it (DMmcMediaDriverFlash::iCardNumber)
1.235 + const TInt KMinMMCBlocksInBuffer = 16 * MMC0_NUMMEDIA;
1.236 + const TInt mmcCchBufLen = KMinMMCBlocksInBuffer << mmcBlkSzLog2;
1.237 +
1.238 + const TInt mmcTotalBufLen = mmcMinorBufLen + mmcCchBufLen;
1.239 +
1.240 + const TInt totalBufLen = mmcTotalBufLen;
1.241 +
1.242 + iMDBuf = reinterpret_cast<TUint8*>(Kern::Alloc(totalBufLen));
1.243 + iMDBufLen = totalBufLen;
1.244 +
1.245 + // setup card size parameters from epoc.ini
1.246 + if (TotalMDiskSize==0)
1.247 + {
1.248 + // Static member variable TotalMDiskSize initialised to zero by default. Set
1.249 + // up static member variables TotalMDiskSize, CSIZE and CSIZE_MULT once and
1.250 + // once only. Use INI file setting if available. Else set to default, IMb.
1.251 + TUint cardSize = Property::GetInt("MultiMediaCardSize");
1.252 + if (cardSize)
1.253 + {
1.254 + // set values to match epoc.ini settings
1.255 + SetupDiskParms(cardSize);
1.256 + }
1.257 + else
1.258 + {
1.259 + // set default values for 1 MB drive
1.260 + TotalMDiskSize=0x100000;
1.261 + CSIZE=127;
1.262 + CSIZE_MULT=2;
1.263 + }
1.264 + }
1.265 +
1.266 + // Initialise each virtual card that will be used on this stack.
1.267 + TInt i;
1.268 + for (i=0 ; i<TotalWinsMMC_Cards; i++)
1.269 + {
1.270 + if ((r=SetupSimulatedCard(i))!=KErrNone)
1.271 + return(r);
1.272 + }
1.273 +
1.274 + // initialize pointers to currently present cards
1.275 +
1.276 + // Slot zero can toggle between no card; card 0 and card 1. The current state is
1.277 + // determined by *Kern::CurrentPBusDevicePtr() and toggled by pressing F4 when F5
1.278 + // (door open) is held down. Because this function is only executed at startup,
1.279 + // assume start with card zero.
1.280 + iCardInfo[0] = iCardPool[0];
1.281 + for (i = 1; i < TotalWinsMMC_CardSlots; ++i)
1.282 + {
1.283 + iCardInfo[i]=iCardPool[i+1];
1.284 + }
1.285 +
1.286 + return(KErrNone);
1.287 + }
1.288 +
1.289 +
1.290 +TInt DWinsMMCStack::CreateBinFileForCard(TInt aCardNum,HANDLE* aHandle,TBool aCreateNew)
1.291 +//
1.292 +// create .bin file in temp directory to contain media area of card.
1.293 +//
1.294 + {
1.295 + const char* emulatorPath = Property::GetString("EmulatorMediaPath");
1.296 + if (!Emulator::CreateAllDirectories(emulatorPath))
1.297 + return Emulator::LastError();
1.298 +
1.299 + TBuf8<KMaxFileName> fn8(_L8(emulatorPath));
1.300 + fn8.Append(_L8("MMCCRD"));
1.301 + fn8.AppendNum(aCardNum);
1.302 + fn8.Append(_L8("A.BIN"));
1.303 + fn8.Append('\0');
1.304 + *aHandle = CreateFileA(
1.305 + (LPCSTR) fn8.Ptr(), // LPCSTR lpFileName,
1.306 + GENERIC_READ | GENERIC_WRITE, // DWORD dwDesiredAccess
1.307 + FILE_SHARE_READ | FILE_SHARE_WRITE, // DWORD dwShareMode
1.308 + NULL, // LPSECURITY_ATTRIBUTES lpSecurityAttributes
1.309 + aCreateNew ? CREATE_ALWAYS : OPEN_ALWAYS, // DWORD dwCreationDisposition
1.310 + FILE_FLAG_RANDOM_ACCESS, // DWORD dwFlagsAndAttributes
1.311 + NULL); // HANDLE hTemplateFile
1.312 +
1.313 + TInt fileSize=GetFileSize(*aHandle,NULL);
1.314 + if (fileSize>TotalMDiskSize)
1.315 + //
1.316 + // The Drive file already exists and size of emulated drive as configured in
1.317 + // epoc.ini has been reduced. Musn't corrupt the emulated drive so delete the
1.318 + // drive file and start from scratch. The emulated drive contents will be
1.319 + // erased.
1.320 + //
1.321 + {
1.322 + CloseHandle(*aHandle);
1.323 + DeleteFileA(
1.324 + (LPCSTR) fn8.Ptr()); // LPCSTR lpFileName,
1.325 + *aHandle = CreateFileA(
1.326 + (LPCSTR) fn8.Ptr(), // LPCSTR lpFileName,
1.327 + GENERIC_READ | GENERIC_WRITE, // DWORD dwDesiredAccess
1.328 + FILE_SHARE_READ | FILE_SHARE_WRITE, // DWORD dwShareMode
1.329 + NULL, // LPSECURITY_ATTRIBUTES lpSecurityAttributes
1.330 + aCreateNew ? CREATE_ALWAYS : OPEN_ALWAYS, // DWORD dwCreationDisposition
1.331 + FILE_FLAG_RANDOM_ACCESS, // DWORD dwFlagsAndAttributes
1.332 + NULL); // HANDLE hTemplateFile
1.333 + }
1.334 +
1.335 + if (*aHandle==INVALID_HANDLE_VALUE)
1.336 + return(MapLastErrorEpoc());
1.337 +
1.338 + if (SetFilePointer(*aHandle,TotalMDiskSize,NULL,FILE_BEGIN)==0xffffffffu
1.339 + || ! SetEndOfFile(*aHandle) )
1.340 + {
1.341 + CloseHandle(*aHandle);
1.342 + return(MapLastErrorEpoc());
1.343 + }
1.344 +
1.345 + return KErrNone;
1.346 + }
1.347 +
1.348 +
1.349 +TInt DWinsMMCStack::SetupSimulatedCard(TInt aCardNum)
1.350 +//
1.351 +// allocate individual card with Win32 file. Only called at bootup, so no cleanup if fails.
1.352 +//
1.353 + {
1.354 + TWinsCardInfo* cip = new TWinsCardInfo;
1.355 + if (cip == 0)
1.356 + return(KErrNoMemory);
1.357 +
1.358 + TUint8 cid[KMMCCIDLength];
1.359 + cid[0] = 'C';
1.360 + cid[1] = 'I';
1.361 + cid[2] = 'D';
1.362 + cid[3] = TUint8('0' + aCardNum);
1.363 + TInt j;
1.364 + for (j = 4; j < KMMCCIDLength - 1; ++j)
1.365 + cid[j] = 'c';
1.366 + cid[KMMCCIDLength - 1] = '#'; // '#' = 0x23, bit zero must be 1
1.367 + cip->iCID=cid;
1.368 +
1.369 + cip->iPWD=new TMediaPassword;
1.370 + if (!cip->iPWD)
1.371 + {
1.372 + delete cip;
1.373 + return(KErrNoMemory);
1.374 + }
1.375 +
1.376 + cip->iState=ECardStateIdle;
1.377 +
1.378 + HANDLE h=NULL;
1.379 + TInt err;
1.380 + if ( (err=CreateBinFileForCard(aCardNum,&h))!=KErrNone )
1.381 + {
1.382 + delete cip;
1.383 + return(err);
1.384 + }
1.385 + cip->iWinHandle=h;
1.386 + iCardPool[aCardNum]=cip;
1.387 + return(KErrNone);
1.388 + }
1.389 +
1.390 +void DWinsMMCStack::SetBusConfigDefaults(TMMCBusConfig& aConfig, TUint aClock)
1.391 +//
1.392 +// Fills BusConfig structure with default values
1.393 +//
1.394 + {
1.395 + const TUint KWinsMaxHwInterfaceClk=104000;
1.396 + const TUint KWinsResponseTimeOut=6400;
1.397 + const TUint KWinsDataTimeOut=40000;
1.398 + const TUint KWinsBusyTimeOut=200000;
1.399 +
1.400 + aConfig.iBusClock = (aClock > KWinsMaxHwInterfaceClk) ? KWinsMaxHwInterfaceClk : aClock;
1.401 + aConfig.iResponseTimeOut=KWinsResponseTimeOut;
1.402 + aConfig.iDataTimeOut=KWinsDataTimeOut;
1.403 + aConfig.iBusyTimeOut=KWinsBusyTimeOut;
1.404 + }
1.405 +
1.406 +void DWinsMMCStack::InitClockOff()
1.407 +//
1.408 +// Switch of the identification mode clock and enable the data transfer mode
1.409 +// clock instead.
1.410 +//
1.411 + {
1.412 + // empty.
1.413 + }
1.414 +
1.415 +void DWinsMMCStack::ASSPReset()
1.416 +//
1.417 +// Stop all activities on the host stack
1.418 +//
1.419 + {
1.420 + // empty.
1.421 + }
1.422 +
1.423 +void DWinsMMCStack::ASSPDisengage()
1.424 +//
1.425 +// Forced release of all ASSP resources
1.426 +//
1.427 + {
1.428 + }
1.429 +
1.430 +void DWinsMMCStack::DoPowerDown()
1.431 +//
1.432 +// Power down the bus
1.433 +//
1.434 + {
1.435 + // Change the state of all virtual cards present to Idle
1.436 + for (TInt i=0 ; i<TotalWinsMMC_CardSlots ; i++)
1.437 + iCardInfo[i]->iState=ECardStateIdle;
1.438 + }
1.439 +
1.440 +
1.441 +LOCAL_C TInt SetMediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,const TDesC8& aPasswd)
1.442 +//
1.443 +// Set the password for local drive 'aLocalDrive', card number 'aCardNum' to 'aPasswd' - as an
1.444 +// environment variable. Note that the card number is only relevant where the emulated drive
1.445 +// supports card hot-swapping (i.e. F4 whilst F5 is held down).
1.446 +//
1.447 + {
1.448 + // Setup the appropriate environment variable string '_EPOC_LocDrv_<locDrvNum>_PWORD_<cardNum>'
1.449 + TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
1.450 +
1.451 + envVar[13]=(TUint16)('0'+aSocketNum);
1.452 + envVar[21]=(TUint16)('0'+aCardNum);
1.453 +
1.454 + // Setup the new value of the environment variable
1.455 + TUint16 envVal[100];
1.456 + TInt len=aPasswd.Length();
1.457 +
1.458 + // the password may be empty if a card's password is cleared
1.459 + if (len>(100-1))
1.460 + return(KErrArgument);
1.461 + memcpy(&envVal[0],reinterpret_cast<const TUint16 *>(aPasswd.Ptr()),len);
1.462 + envVal[len>>1]='\0';
1.463 +
1.464 + // Now set the new value for the environment variable
1.465 + if (SetEnvironmentVariable(envVar,&envVal[0]))
1.466 + return(KErrNone);
1.467 +
1.468 + return KErrGeneral;
1.469 + }
1.470 +
1.471 +LOCAL_C TInt MediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,TDes8& aPasswd)
1.472 +//
1.473 +// Get the password for local drive 'aLocalDrive', card number 'aCardNum' into 'aPasswd' - from
1.474 +// an environment variable. Note that the card number is only relevant where the emulated drive
1.475 +// supports card hot-swapping (i.e. F4 whilst F5 is held down).
1.476 +//
1.477 + {
1.478 + TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
1.479 +
1.480 + envVar[13]=(TUint16)('0'+aSocketNum);
1.481 + envVar[21]=(TUint16)('0'+aCardNum);
1.482 +
1.483 + TUint16 envVal[100]; // To hold the value of the retreived environment variable
1.484 +
1.485 + DWORD len=GetEnvironmentVariable(envVar,&envVal[0],100);
1.486 + if (len>(TUint)100)
1.487 + return(KErrGeneral);
1.488 + if (len)
1.489 + {
1.490 + // Found the requested environment variable so there is a password for this local drive / card.
1.491 + if ((len<<1)<=KMaxMediaPassword)
1.492 + {
1.493 + aPasswd.FillZ(KMaxMediaPassword);
1.494 + aPasswd.Zero();
1.495 + aPasswd.Copy(reinterpret_cast<TUint8*>(&envVal[0]),len<<1);
1.496 + return(KErrNone);
1.497 + }
1.498 + else
1.499 + return(KErrGeneral);
1.500 + }
1.501 +
1.502 + return(KErrNotFound);
1.503 + }
1.504 +
1.505 +TMMCErr DWinsMMCStack::DoPowerUpSM()
1.506 +//
1.507 +// State Machine functions implemented in ASSP layer
1.508 +//
1.509 + {
1.510 + enum states
1.511 + {
1.512 + EStBegin=0,
1.513 + EStEnd
1.514 + };
1.515 +
1.516 + SMF_BEGIN
1.517 +
1.518 + __KTRACE_OPT(KPBUS1, Kern::Printf("DoPowerUpSM: BEGIN"));
1.519 +
1.520 + if( MMCSocket()->iVcc->SetState(EPsuOnCurLimit) != KErrNone )
1.521 + return( KMMCErrHardware );
1.522 +
1.523 + for (TInt i=0 ; i<TotalWinsMMC_CardSlots ; i++)
1.524 + {
1.525 + // Attempt to retrieve a password for this card from environment settings (as long as this
1.526 + // isn't card0 and we are simulating this is not present)
1.527 + TInt cardNum=(i==0) ? *Wins::CurrentPBusDevicePtr() : i;
1.528 + if (cardNum>=0 && MediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[i]->iPWD))==KErrNone)
1.529 + {
1.530 + // Card has a password so lock it automatically on power up.
1.531 + iCardInfo[i]->iIsLocked=(iCardInfo[i]->iPWD->Length() > 0);
1.532 + }
1.533 + else
1.534 + iCardInfo[i]->iIsLocked=EFalse;
1.535 +
1.536 + iCardInfo[i]->iRCA=0x0001; // Default RCA - spec 2.2, s4.2.1, 5.4
1.537 + }
1.538 +
1.539 + ReportPowerUp();
1.540 +
1.541 + SMF_END
1.542 + }
1.543 +
1.544 +TMMCErr DWinsMMCStack::InitClockOnSM()
1.545 +//
1.546 +// Switch on the identification mode clock
1.547 +//
1.548 + {
1.549 + enum states
1.550 + {
1.551 + EStBegin=0,
1.552 + EStEnd
1.553 + };
1.554 + SMF_BEGIN
1.555 +
1.556 + SMF_END
1.557 + }
1.558 +
1.559 +TMMCErr DWinsMMCStack::ModifyCardCapabilitySM()
1.560 +//
1.561 +// This function provides a chance to modify the capability of paticular cards.
1.562 +// Licensee may overide this function to modify certain card's capability as needed.
1.563 +// A state machine is needed in derived function and function of base class should be
1.564 +// called in order to act more generic behaviour.
1.565 +//
1.566 + {
1.567 + enum states
1.568 + {
1.569 + EStBegin=0,
1.570 + EStDone,
1.571 + EStEnd
1.572 + };
1.573 +
1.574 + SMF_BEGIN
1.575 +
1.576 + SMF_INVOKES( DMMCStack::BaseModifyCardCapabilitySMST, EStDone )
1.577 +
1.578 + SMF_STATE(EStDone)
1.579 +
1.580 + SMF_END
1.581 + }
1.582 +
1.583 +TInt DWinsMMCStack::GetTargetSlotNumber(TBool anRCASupplied,const TRCA& anRCA)
1.584 +//
1.585 +// Attempt to determine the slot number of the target card. If the received command
1.586 +// contained an RCA then 'anRCASupplied' will be ETrue - in which case, 'anRCA'
1.587 +// contains the RCA in question.
1.588 +//
1.589 + {
1.590 + TInt selCardIdx = KBroadcastToAllCards;
1.591 +
1.592 + // if an RCA was supplied, then work out which card slot it corresponds to
1.593 + if (anRCASupplied)
1.594 + {
1.595 + for (TInt i = 0 ; i < TotalWinsMMC_CardSlots ; ++i)
1.596 + {
1.597 + if (iCardInfo[i]->iRCA==anRCA)
1.598 + {
1.599 + selCardIdx=i;
1.600 + break;
1.601 + }
1.602 + }
1.603 + }
1.604 + // else search for currently selected card
1.605 + else
1.606 + {
1.607 + for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
1.608 + {
1.609 + if (iCardInfo[i]->iState == ECardStateTran)
1.610 + {
1.611 + selCardIdx = i;
1.612 + break;
1.613 + }
1.614 + }
1.615 + }
1.616 +
1.617 + return(selCardIdx);
1.618 + }
1.619 +
1.620 +TMMCErr DWinsMMCStack::IssueMMCCommandSM()
1.621 +//
1.622 +// Top level ASSP command executor
1.623 +//
1.624 + {
1.625 + enum states
1.626 + {
1.627 + EStBegin=0,
1.628 + EStDoubleBuffer,
1.629 + EStCommandDone,
1.630 + EStEnd
1.631 + };
1.632 +
1.633 + TMMCCommandDesc& cmd = Command();
1.634 +
1.635 + TRCA tgtRCA=0;
1.636 + TBool supRCA=EFalse;
1.637 + // Record the RCA if it is embedded in the argument [31:16].
1.638 + if (cmd.iCommand == ECmdSetRelativeAddr || cmd.iCommand == ECmdSelectCard
1.639 + || cmd.iCommand == ECmdSendCSD || cmd.iCommand == ECmdSendCID
1.640 + || cmd.iCommand == ECmdSendStatus || cmd.iCommand == ECmdGoInactiveState
1.641 + || cmd.iCommand == ECmdFastIO || cmd.iCommand == ECmdAppCmd )
1.642 + {
1.643 + supRCA=ETrue;
1.644 + tgtRCA=TUint16(cmd.iArgument >> 16);
1.645 + }
1.646 +
1.647 + // Attempt to determine the target card using supplied RCA
1.648 + TInt selCardIdx=GetTargetSlotNumber(supRCA,tgtRCA);
1.649 +
1.650 + // Simulation of card swapping (i.e. F4/F5) is performed on slot 0. If this is currently
1.651 + // set to simulate no card present and the issued command is targetted specifically at the
1.652 + // card in slot 0 (i.e. not a broadcast command) then timeout.
1.653 + if (selCardIdx==0 && *Wins::CurrentPBusDevicePtr() < 0)
1.654 + return(KMMCErrResponseTimeOut);
1.655 +
1.656 + // If an RCA was supplied but didn't coincide with the RCAs of any cards present
1.657 + // then timeout (Ignore SET_RCA and APP_CMD as these are sent before RCAs are assigned).
1.658 + if (supRCA && selCardIdx==KBroadcastToAllCards &&
1.659 + cmd.iCommand != ECmdSetRelativeAddr && cmd.iCommand != ECmdAppCmd)
1.660 + return(KMMCErrResponseTimeOut);
1.661 +
1.662 + HANDLE winHandle=NULL;
1.663 +
1.664 + // CMD42 is a data transfer command. That means the R1 response that it returns
1.665 + // immediately is the state it is in on receiving the data block, and not after
1.666 + // processing it. If the data block is invalid then LOCK_UNLOCK_FAILED will be
1.667 + // set in the R1 response which is sent in reply to the next command.
1.668 +
1.669 + TBool nextCMD42Failed = EFalse;
1.670 + TBool lock_unlock_failed=EFalse;
1.671 +
1.672 + // When the card is locked, it will only respond to basic command class (0) and
1.673 + // lock card command class (7). An exception is CMD16. This is sent before CMD42,
1.674 + // but is classified (MMC Spec 23.2, table 5) as belonging to classes 2 and 4.
1.675 + // For data transfer commands, LOCK_UNLOCK_FAIL is set in response to the following
1.676 + const TMMCCommandEnum origCmd(cmd.iCommand);
1.677 + if ( selCardIdx != KBroadcastToAllCards
1.678 + && iCardInfo[selCardIdx]->iIsLocked // If locked and not in CCC 0 or 7 then skip
1.679 + && ( ((cmd.iSpec.iCommandClass & (KMMCCmdClassBasic | KMMCCmdClassLockCard)) == 0)
1.680 + && cmd.iCommand != ECmdSetBlockLen ) )
1.681 + {
1.682 + lock_unlock_failed = ETrue; // try to access locked card
1.683 + cmd.iCommand = TMMCCommandEnum(-1); // skip command processing
1.684 + }
1.685 +
1.686 + SMF_BEGIN
1.687 +
1.688 + TBool rto = EFalse; // response timeout
1.689 + switch (cmd.iCommand)
1.690 + {
1.691 + case ECmdGoIdleState: // CMD0
1.692 + {
1.693 + for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
1.694 + iCardInfo[i]->iState = ECardStateIdle;
1.695 + }
1.696 + break;
1.697 +
1.698 + case ECmdSendOpCond: // CMD1
1.699 + {
1.700 + for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
1.701 + iCardInfo[i]->iState = ECardStateReady;
1.702 +
1.703 + // bit32 is set to indicate cards are not still powering up
1.704 + TUint32 r3 = KMMCWinsCardOCRValue | KMMCOCRBusy;
1.705 + TMMC::BigEndian4Bytes(cmd.iResponse, r3);
1.706 + }
1.707 + break;
1.708 +
1.709 + case ECmdAllSendCID: // CMD2
1.710 + {
1.711 + TInt idx = FindAnyCardInStack(ECardStateReady);
1.712 +
1.713 + if (idx == -1)
1.714 + rto = ETrue;
1.715 + else
1.716 + {
1.717 + iCardInfo[idx]->iCID.Copy(cmd.iResponse);
1.718 + iCardInfo[idx]->iState = ECardStateIdent;
1.719 + }
1.720 + }
1.721 + break;
1.722 +
1.723 + case ECmdSetRelativeAddr: // CMD3
1.724 + {
1.725 + TInt idx = FindOneCardInStack(ECardStateIdent);
1.726 + iCardInfo[idx]->iRCA = tgtRCA;
1.727 + iCardInfo[idx]->iState=ECardStateStby;
1.728 + selCardIdx = idx; // set R1 response at end
1.729 + }
1.730 + break;
1.731 +
1.732 + case ECmdSelectCard: // CMD7
1.733 + {
1.734 + // switch to broadcast mode so the currently selected and new cards
1.735 + // receive the command simultaneously.
1.736 +
1.737 + TInt idx = FindAnyCardInStack(ECardStateTran);
1.738 + if (idx != -1)
1.739 + iCardInfo[idx]->iState = ECardStateStby;
1.740 + iCardInfo[selCardIdx]->iState = ECardStateTran;
1.741 + }
1.742 + break;
1.743 +
1.744 + case ECmdSendStatus:
1.745 + // R1 response so status return as for any other R1 command.
1.746 + break;
1.747 +
1.748 + case ECmdReadSingleBlock:
1.749 + case ECmdReadMultipleBlock:
1.750 + {
1.751 + winHandle=iCardInfo[selCardIdx]->iWinHandle;
1.752 +
1.753 + if ( cmd.iSpec.iUseStopTransmission && cmd.iBlockLength >= cmd.iTotalLength)
1.754 + return( KMMCErrNotSupported );
1.755 +
1.756 + TMMCErr err;
1.757 + TInt pos = cmd.iArgument;
1.758 + if (SetFilePointer(winHandle,pos,NULL,FILE_BEGIN)==0xffffffffu)
1.759 + err=MapLastErrorMmc();
1.760 + else
1.761 + {
1.762 + iBytesToTransfer = cmd.BufferLength();
1.763 + err = ReadWriteData(selCardIdx, cmd.iDataMemoryP, iBytesToTransfer, cmd.iSpec.iDirection);
1.764 + if(err == KMMCErrNone)
1.765 + {
1.766 + Session().RequestMoreData();
1.767 + SMF_WAITS(EStDoubleBuffer);
1.768 + }
1.769 + }
1.770 + if (err!=KMMCErrNone)
1.771 + return(err);
1.772 + }
1.773 + break;
1.774 +
1.775 + // ------------------------------------------------------------------
1.776 + case ECmdWriteBlock:
1.777 + case ECmdWriteMultipleBlock:
1.778 + {
1.779 + HANDLE h = iCardInfo[selCardIdx]->iWinHandle;
1.780 +
1.781 + TMMCErr err;
1.782 + TInt pos = cmd.iArgument;
1.783 + if (SetFilePointer(h, pos, NULL, FILE_BEGIN)==0xffffffffu)
1.784 + err = MapLastErrorMmc();
1.785 + else
1.786 + {
1.787 + iBytesToTransfer = cmd.BufferLength();
1.788 + err = ReadWriteData(selCardIdx, cmd.iDataMemoryP, iBytesToTransfer, cmd.iSpec.iDirection);
1.789 + if(err == KMMCErrNone)
1.790 + {
1.791 + Session().RequestMoreData();
1.792 + SMF_WAITS(EStDoubleBuffer);
1.793 + }
1.794 + }
1.795 +
1.796 + if (err!=KMMCErrNone)
1.797 + return(err);
1.798 + }
1.799 + break;
1.800 +
1.801 + case ECmdAppCmd:
1.802 + rto = ETrue;
1.803 + break;
1.804 +
1.805 + case ECmdSendCSD:
1.806 + {
1.807 + iCardInfo[selCardIdx]->GetCSD(cmd.iResponse);
1.808 + break;
1.809 + }
1.810 +
1.811 + // ------------------------------------------------------------------
1.812 + case ECmdLockUnlock:
1.813 + // in EPOC, Lock() does not actually lock the card. It just sets the
1.814 + // password. This means that the card is still accessible to the user,
1.815 + // but must be unlocked the next time it is powered up.
1.816 +
1.817 + // a real card will transiently go into rcv and prg state while processing
1.818 + // this command. When finished, it will fall back into tran state.
1.819 + // The R1 response is sent immediately after CMD42. CIMReadWriteBlocksSM()
1.820 + // sends CMD13 to find out whether or not LOCK_UNLOCK_FAIL was set.
1.821 +
1.822 + // the asserts in this case protect against invalid data being sent from the
1.823 + // media driver. A real card would fail these corrupt data blocks.
1.824 +
1.825 + {
1.826 +#ifdef __CARD0_NOT_LOCKABLE__
1.827 + if (*Wins::CurrentPBusDevicePtr() == 0)
1.828 + return KMMCErrNotSupported;
1.829 +#endif
1.830 +#ifdef __CARD1_NOT_LOCKABLE__
1.831 + if (*Wins::CurrentPBusDevicePtr() == 1)
1.832 + return KMMCErrNotSupported;
1.833 +#endif
1.834 + const TInt8 cmd_byte(*cmd.iDataMemoryP);
1.835 + __ASSERT_DEBUG( // ensure not CLR_PWD && SET_PWD
1.836 + !((cmd_byte & KMMCLockUnlockClrPwd) && (cmd_byte & KMMCLockUnlockSetPwd)),
1.837 + DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
1.838 +
1.839 + __ASSERT_DEBUG( // ensure not FORCE_ERASE with CLR_PWD or SET_PWD
1.840 + !((cmd_byte & KMMCLockUnlockErase) && (cmd_byte & (KMMCLockUnlockSetPwd | KMMCLockUnlockClrPwd))),
1.841 + DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
1.842 +
1.843 + __ASSERT_DEBUG( // not actually lock a card while setting the password
1.844 + ((cmd_byte & (KMMCLockUnlockLockUnlock | KMMCLockUnlockSetPwd)) != (KMMCLockUnlockLockUnlock | KMMCLockUnlockSetPwd)),
1.845 + DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCLockAttempt) );
1.846 +
1.847 + if (cmd_byte & KMMCLockUnlockErase) // Forced Erase of a locked card
1.848 + {
1.849 + if (iCardInfo[selCardIdx]->iIsLocked) // Forced erase when locked
1.850 + {
1.851 + iCardInfo[selCardIdx]->iPWD->Zero(); // Remove the password
1.852 + iCardInfo[selCardIdx]->iIsLocked = EFalse;
1.853 + nextCMD42Failed = EFalse;
1.854 +
1.855 + TInt cardNum = (selCardIdx==0) ? *Wins::CurrentPBusDevicePtr() : selCardIdx;
1.856 + SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[selCardIdx]->iPWD));
1.857 +
1.858 + // Erase then entire contents of the emulated drive
1.859 + HANDLE handle = iCardInfo[selCardIdx]->iWinHandle;
1.860 + CloseHandle(handle);
1.861 + iCardInfo[selCardIdx]->iWinHandle = NULL;
1.862 + if(CreateBinFileForCard(selCardIdx, &handle, ETrue) != KErrNone)
1.863 + return(MapLastErrorMmc());
1.864 + iCardInfo[selCardIdx]->iWinHandle = handle;
1.865 + }
1.866 + else // Forced erase when unlocked (illegal)
1.867 + {
1.868 + nextCMD42Failed = ETrue;
1.869 + }
1.870 + }
1.871 + else
1.872 + {
1.873 + const TInt8 pwd_len = *(cmd.iDataMemoryP + 1);
1.874 + const TPtrC8 pwd(cmd.iDataMemoryP + 2, pwd_len);
1.875 +
1.876 + if ((cmd_byte & KMMCLockUnlockClrPwd) != 0) // CLR_PWD == 1
1.877 + {
1.878 + __ASSERT_DEBUG(
1.879 + pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
1.880 + DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand));
1.881 +
1.882 + if (iCardInfo[selCardIdx]->iIsLocked) // clear when locked
1.883 + nextCMD42Failed = ETrue;
1.884 + else // clear when unlocked
1.885 + {
1.886 + if (iCardInfo[selCardIdx]->iPWD->Compare(pwd) != 0) // clear when unlocked with wrong password
1.887 + {
1.888 + nextCMD42Failed = ETrue;
1.889 + lock_unlock_failed = ETrue;
1.890 + }
1.891 + else // clear when unlocked with right password
1.892 + {
1.893 + // Clear from password store
1.894 + iCardInfo[selCardIdx]->iPWD->Zero();
1.895 + iCardInfo[selCardIdx]->iIsLocked = EFalse;
1.896 + nextCMD42Failed = EFalse;
1.897 +
1.898 + // Clear from environment settings
1.899 + TInt cardNum=(selCardIdx==0) ? *Wins::CurrentPBusDevicePtr() : selCardIdx; // Can't be -1 at this stage
1.900 + SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[selCardIdx]->iPWD));
1.901 + }
1.902 + }
1.903 + }
1.904 + else if ((cmd_byte & KMMCLockUnlockSetPwd) == 0) // SET_PWD == 0: unlock
1.905 + {
1.906 + __ASSERT_DEBUG(
1.907 + pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
1.908 + DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
1.909 +
1.910 + if (! iCardInfo[selCardIdx]->iIsLocked) // unlock when unlocked
1.911 + nextCMD42Failed = ETrue;
1.912 + else
1.913 + {
1.914 + if (iCardInfo[selCardIdx]->iPWD->Compare(pwd) != 0) // unlock when locked with wrong password
1.915 + {
1.916 + nextCMD42Failed = ETrue;
1.917 + lock_unlock_failed = ETrue;
1.918 + }
1.919 + else // unlock when locked with right password
1.920 + {
1.921 + iCardInfo[selCardIdx]->iIsLocked = EFalse;
1.922 + nextCMD42Failed = EFalse;
1.923 + }
1.924 + }
1.925 + }
1.926 + else if ((cmd_byte & KMMCLockUnlockSetPwd) == KMMCLockUnlockSetPwd) // SET_PWD == 1
1.927 + {
1.928 + __ASSERT_DEBUG(
1.929 + cmd_byte & KMMCLockUnlockSetPwd,
1.930 + DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
1.931 +
1.932 + // if pwd_len < iCardInfo[selCardIdx]->iPWD->Length() then data block must be invalid.
1.933 + // This can be caused by bad user input rather than inaccurate formation.
1.934 + if (!( pwd_len >= iCardInfo[selCardIdx]->iPWD->Length()
1.935 + && pwd_len <= iCardInfo[selCardIdx]->iPWD->Length() + KMaxMediaPassword ))
1.936 + {
1.937 + nextCMD42Failed = ETrue;
1.938 + }
1.939 + else
1.940 + {
1.941 + TUint16 env_Var[]=L"_EPOC_PWD_LEN";
1.942 + TUint16 env_Val[2];
1.943 + TInt r=GetEnvironmentVariable(env_Var,&env_Val[0],2);
1.944 + r=r;//This code is added to suppress WINS warnings
1.945 + __ASSERT_DEBUG(r!=0,Kern::PanicCurrentThread(_L("PBUS-MMC-WINS-GETENV"),0));
1.946 + const TInt old_pwd_len=env_Val[0]-1;
1.947 + TPtrC8 old_pwd(cmd.iDataMemoryP + 2, old_pwd_len);
1.948 + TPtrC8 new_pwd(cmd.iDataMemoryP + 2 + old_pwd_len, pwd_len - old_pwd_len);
1.949 +
1.950 + // card must not be locked and supplied current password must be correct
1.951 + if (iCardInfo[selCardIdx]->iIsLocked || iCardInfo[selCardIdx]->iPWD->Compare(old_pwd) != 0)
1.952 + {
1.953 + nextCMD42Failed = ETrue;
1.954 + lock_unlock_failed = ETrue;
1.955 + }
1.956 + else
1.957 + {
1.958 + // Set in password store
1.959 + iCardInfo[selCardIdx]->iPWD->Copy(new_pwd);
1.960 + nextCMD42Failed = EFalse;
1.961 +
1.962 + // Set in environment settings
1.963 + TInt cardNum=(selCardIdx==0) ? *Wins::CurrentPBusDevicePtr() : selCardIdx; // Can't be -1 at this stage
1.964 + SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[selCardIdx]->iPWD));
1.965 + }
1.966 + }
1.967 + }
1.968 + else if ((cmd_byte & KMMCLockUnlockLockUnlock) == KMMCLockUnlockLockUnlock)
1.969 + {
1.970 + __ASSERT_DEBUG(
1.971 + pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
1.972 + DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
1.973 +
1.974 + if (iCardInfo[selCardIdx]->iIsLocked) // lock when locked
1.975 + nextCMD42Failed = ETrue;
1.976 + else
1.977 + {
1.978 + if (iCardInfo[selCardIdx]->iPWD->Compare(pwd) != 0) // lock with wrong password
1.979 + {
1.980 + nextCMD42Failed = ETrue;
1.981 + lock_unlock_failed = ETrue;
1.982 + }
1.983 + else // lock with right password
1.984 + {
1.985 + iCardInfo[selCardIdx]->iIsLocked = ETrue;
1.986 + nextCMD42Failed = EFalse;
1.987 + }
1.988 + }
1.989 + }
1.990 + else
1.991 + {
1.992 + __ASSERT_DEBUG(EFalse, DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCLockAttempt) );
1.993 + }
1.994 + }
1.995 + } // case ECmdLockUnlock
1.996 + break;
1.997 +
1.998 + case ECmdSetBlockCount:
1.999 + {
1.1000 + // Only supported in version 3.1
1.1001 + if(Session().iCardP->CSD().SpecVers() != 3)
1.1002 + {
1.1003 + return(KMMCErrNotSupported);
1.1004 + }
1.1005 + }
1.1006 + break;
1.1007 +
1.1008 + // ------------------------------------------------------------------
1.1009 + default:
1.1010 + break;
1.1011 + }
1.1012 +
1.1013 + if (rto)
1.1014 + {
1.1015 + return(KMMCErrResponseTimeOut);
1.1016 + }
1.1017 +
1.1018 + // drop through to command done...
1.1019 +
1.1020 + SMF_STATE(EStCommandDone)
1.1021 +
1.1022 + cmd.iCommand = origCmd;
1.1023 + // If this is an R1 or R1b response type command then return card status as a response
1.1024 + if ( selCardIdx != KBroadcastToAllCards
1.1025 + && (cmd.iSpec.iResponseType==ERespTypeR1 || cmd.iSpec.iResponseType==ERespTypeR1B) )
1.1026 + {
1.1027 + TUint32 resp(
1.1028 + iCardInfo[selCardIdx]->iState
1.1029 + | ((iCardInfo[selCardIdx]->iIsLocked ? 1 : 0) << 25)
1.1030 + | ((lock_unlock_failed ? 1 : 0) << 24) );
1.1031 +
1.1032 + if (iCMD42Failed) // previous CMD42
1.1033 + {
1.1034 + resp |= KMMCStatErrLockUnlock;
1.1035 + nextCMD42Failed = EFalse;
1.1036 + }
1.1037 + iCMD42Failed = nextCMD42Failed;
1.1038 + TMMC::BigEndian4Bytes(&cmd.iResponse[0],resp); // Ignore bits 47-40
1.1039 + }
1.1040 +
1.1041 + SMF_GOTOS(EStEnd);
1.1042 +
1.1043 + SMF_STATE(EStDoubleBuffer)
1.1044 +
1.1045 + cmd.iBytesDone += iBytesToTransfer;
1.1046 +
1.1047 + if(cmd.iBytesDone < cmd.iTotalLength)
1.1048 + {
1.1049 + iBytesToTransfer = cmd.BufferLength();
1.1050 + TMMCErr err = ReadWriteData(selCardIdx, cmd.iDataMemoryP, iBytesToTransfer, cmd.iSpec.iDirection);
1.1051 + if(err == KMMCErrNone)
1.1052 + {
1.1053 + Session().RequestMoreData();
1.1054 + SMF_WAITS(EStDoubleBuffer);
1.1055 + }
1.1056 + else
1.1057 + {
1.1058 + return(err);
1.1059 + }
1.1060 + }
1.1061 + else
1.1062 + {
1.1063 + SMF_GOTOS(EStCommandDone);
1.1064 + }
1.1065 +
1.1066 + SMF_END
1.1067 + }
1.1068 +
1.1069 +
1.1070 +TMMCErr DWinsMMCStack::ReadWriteData(TInt aCardIdx, TUint8* aDataP, TUint32 aLength, TMMCCmdDirEnum aDir)
1.1071 + {
1.1072 + TMMCErr err = KMMCErrNone;
1.1073 +
1.1074 + HANDLE h = iCardInfo[aCardIdx]->iWinHandle;
1.1075 +
1.1076 + DWORD res;
1.1077 + TBool success;
1.1078 +
1.1079 + if(aDir == EDirWrite)
1.1080 + {
1.1081 + success = WriteFile(h, (LPCVOID)aDataP, aLength, &res, NULL);
1.1082 + }
1.1083 + else
1.1084 + {
1.1085 + success = ReadFile(h, (LPVOID)aDataP, aLength, &res, NULL);
1.1086 + }
1.1087 +
1.1088 + if (!success)
1.1089 + {
1.1090 + err=MapLastErrorMmc();
1.1091 + }
1.1092 + else if (res != (DWORD)aLength)
1.1093 + {
1.1094 + err=KMMCErrGeneral;
1.1095 + }
1.1096 +
1.1097 + return(err);
1.1098 + }
1.1099 +
1.1100 +
1.1101 +TInt DWinsMMCStack::FindAnyCardInStack(TMMCardStateEnum aState)
1.1102 +//
1.1103 +// first first active card in supplied state. Return -1 if
1.1104 +// no active card is in supplied state.
1.1105 +//
1.1106 + {
1.1107 + for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
1.1108 + {
1.1109 + if (iCardInfo[i]->iState == aState)
1.1110 + return i;
1.1111 + }
1.1112 + return -1;
1.1113 + }
1.1114 +
1.1115 +TInt DWinsMMCStack::FindFirstCardInStack(TMMCardStateEnum aState)
1.1116 +//
1.1117 +// find card which is active on bus and in supplied state.
1.1118 +// There can be more than one active card in the the supplied state,
1.1119 +// but there should be at least one.
1.1120 +//
1.1121 + {
1.1122 + TInt idx = -1;
1.1123 + for (TInt i = 0; idx != -1 && i < TotalWinsMMC_CardSlots; ++i)
1.1124 + {
1.1125 + if (iCardInfo[i]->iState == aState)
1.1126 + idx = i;
1.1127 + }
1.1128 +
1.1129 + __ASSERT_DEBUG(idx != -1, DWinsMMCStack::Panic(DWinsMMCStack::EStkFFCNoneSel));
1.1130 + return idx;
1.1131 + }
1.1132 +
1.1133 +TInt DWinsMMCStack::FindOneCardInStack(TMMCardStateEnum aState)
1.1134 +//
1.1135 +// find card which is active on bus and in supplied state.
1.1136 +// There should be exactly one active card in the supplied state.
1.1137 +//
1.1138 + {
1.1139 + TInt idx = -1;
1.1140 + for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
1.1141 + {
1.1142 + if (iCardInfo[i]->iState == aState)
1.1143 + {
1.1144 + __ASSERT_DEBUG(idx == -1, DWinsMMCStack::Panic(DWinsMMCStack::EStkFOCMultiSel));
1.1145 + idx = i;
1.1146 + }
1.1147 + }
1.1148 +
1.1149 + __ASSERT_DEBUG(idx != -1, DWinsMMCStack::Panic(DWinsMMCStack::EStkFOCNoneSel));
1.1150 + return idx;
1.1151 + }
1.1152 +
1.1153 +void DWinsMMCStack::SetupDiskParms(TUint aDiskSize)
1.1154 + {
1.1155 +//
1.1156 +// setup parms for emulated mmc disk size
1.1157 +//
1.1158 + // force a minimum of 32 KB total size
1.1159 + if (aDiskSize<32)
1.1160 + aDiskSize=32;
1.1161 + // first setup the CSD parameters
1.1162 + CSIZE_MULT = 0;
1.1163 + TUint newCSIZE = aDiskSize>>1; // with zero multiplier 1 + size parameter = size in KB / 2
1.1164 + while((newCSIZE>0xfff)&&(CSIZE_MULT<7))
1.1165 + // size parameter 12 bits, multiplier 3 bits
1.1166 + {
1.1167 + // size parameter too big and multiplier still has room to
1.1168 + // grow so increase multiplier and reduce size parameter
1.1169 + CSIZE_MULT++;
1.1170 + newCSIZE = aDiskSize>>(1+CSIZE_MULT);
1.1171 + }
1.1172 + CSIZE = newCSIZE;
1.1173 + // as CSIZE = 1 + CSIZE
1.1174 + CSIZE--;
1.1175 + // restrict to 12 bits
1.1176 + if (CSIZE>0xfff)
1.1177 + CSIZE=0xfff;
1.1178 + // now setup TotalDiskSize
1.1179 + TotalMDiskSize = 512 * (1+CSIZE) * (1<<(2+CSIZE_MULT));
1.1180 + }
1.1181 +
1.1182 +// ======== TWinsMMCMediaChange ========
1.1183 +
1.1184 +#pragma warning( disable : 4355 ) // this used in initializer list
1.1185 +DWinsMMCMediaChange::DWinsMMCMediaChange(TInt aMediaChangeNum)
1.1186 +//
1.1187 +// Constructor
1.1188 +//
1.1189 + : DMMCMediaChange(aMediaChangeNum),
1.1190 + iMediaChangeEnable(ETrue)
1.1191 + {
1.1192 +
1.1193 + iMediaDoorCloseReload=2; // Units: In theory-20ms, Actual-100ms
1.1194 + }
1.1195 +#pragma warning( default : 4355 )
1.1196 +
1.1197 +TInt DWinsMMCMediaChange::Create()
1.1198 +//
1.1199 +// Initialiser.
1.1200 +//
1.1201 + {
1.1202 + return(DMediaChangeBase::Create());
1.1203 + }
1.1204 +
1.1205 +void DWinsMMCMediaChange::DoorOpenService()
1.1206 +//
1.1207 +// Handle the media change (this function, never postponed is called on media
1.1208 +// change interrupt).
1.1209 +//
1.1210 + {
1.1211 + Disable(); // Disable interrupt until door closes again.
1.1212 + iDoorOpenDfc.Enque();
1.1213 + }
1.1214 +
1.1215 +void DWinsMMCMediaChange::DoDoorOpen()
1.1216 +//
1.1217 +// Handle media door open (called on media door open interrupt).
1.1218 +//
1.1219 + {
1.1220 + iDoorClosedCount=iMediaDoorCloseReload;
1.1221 + // Just start a ticklink to poll for door closing
1.1222 + iTickLink.Periodic(KMediaChangeTickInterval,DWinsMMCMediaChange::Tick,this);
1.1223 + }
1.1224 +
1.1225 +void DWinsMMCMediaChange::DoDoorClosed()
1.1226 +//
1.1227 +// Handle media door closing
1.1228 +//
1.1229 + {
1.1230 + iTickLink.Cancel(); // Doesn't matter if wasn't enabled
1.1231 + Enable(); // Re-enable door interrupts
1.1232 +
1.1233 + // While the door was open the user may have changed the card in slot 0
1.1234 + if (iStackP && *Wins::CurrentPBusDevicePtr() >= 0)
1.1235 + iStackP->iCardInfo[0]=iStackP->iCardPool[*Wins::CurrentPBusDevicePtr()];
1.1236 + }
1.1237 +
1.1238 +void DWinsMMCMediaChange::ForceMediaChange()
1.1239 +//
1.1240 +// Force media change
1.1241 +//
1.1242 + {
1.1243 + DoorOpenService();
1.1244 + }
1.1245 +
1.1246 +TMediaState DWinsMMCMediaChange::MediaState()
1.1247 +//
1.1248 +// Return status of media changed signal.
1.1249 +//
1.1250 + {
1.1251 + if (iDoorClosedCount>0)
1.1252 + return(EDoorOpen);
1.1253 + return( (*Wins::MediaDoorOpenPtr())?EDoorOpen:EDoorClosed);
1.1254 + }
1.1255 +
1.1256 +void DWinsMMCMediaChange::Tick(TAny *aPtr)
1.1257 +//
1.1258 +// Called on the tick to poll for door closing (called on DFC).
1.1259 +//
1.1260 + {
1.1261 +
1.1262 + ((DWinsMMCMediaChange*)aPtr)->TickService();
1.1263 + }
1.1264 +
1.1265 +void DWinsMMCMediaChange::TickService()
1.1266 +//
1.1267 +// Called on the tick to poll for door closing (called on DFC).
1.1268 +//
1.1269 + {
1.1270 +
1.1271 + __ASSERT_DEBUG(iDoorClosedCount>=0,DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCMediaChangeTickFault));
1.1272 +
1.1273 + if (!(*Wins::MediaDoorOpenPtr()))
1.1274 + {
1.1275 + if (iDoorClosedCount > 0)
1.1276 + {
1.1277 + if (--iDoorClosedCount == 0)
1.1278 + {
1.1279 + iTickLink.Cancel(); // cancel door closed timer
1.1280 + DoorClosedService();
1.1281 + }
1.1282 + }
1.1283 + }
1.1284 + else
1.1285 + iDoorClosedCount=iMediaDoorCloseReload; // Door open so start again.
1.1286 + }
1.1287 +
1.1288 +void DWinsMMCMediaChange::Enable()
1.1289 +//
1.1290 +// Enable media change
1.1291 +//
1.1292 + {
1.1293 +
1.1294 + iMediaChangeEnable=ETrue;
1.1295 + }
1.1296 +
1.1297 +void DWinsMMCMediaChange::Disable()
1.1298 +//
1.1299 +// Disable media change
1.1300 +//
1.1301 + {
1.1302 +
1.1303 + iMediaChangeEnable=EFalse;
1.1304 + }
1.1305 +
1.1306 +void DWinsMMCMediaChange::MediaChangeCallBack(TAny *aPtr)
1.1307 +//
1.1308 +// Static called on media change
1.1309 +//
1.1310 + {
1.1311 + DWinsMMCMediaChange* mc=(DWinsMMCMediaChange*)aPtr;
1.1312 + if (mc!=NULL&&mc->iMediaChangeEnable)
1.1313 + mc->DoorOpenService();
1.1314 + }
1.1315 +
1.1316 +// ======== TWinsCardInfo ========
1.1317 +
1.1318 +void TWinsCardInfo::GetCSD(TUint8* aResp) const
1.1319 + {
1.1320 + // Bits 127-96
1.1321 + TUint32 csd=(KCsdStructure<<30); /* CSD_STRUCTURE */
1.1322 + csd|= (KCsdSpecVers<<26); /* SPEC_VERS */
1.1323 + csd|= (0x0E<<16); /* TAAC: 1mS */
1.1324 + csd|= (0x0A<<8); /* NSAC: 1000 */
1.1325 + csd|= (0x59); /* TRAN_SPEED: 5.0Mbit/s */
1.1326 + TMMC::BigEndian4Bytes(&aResp[0],csd);
1.1327 +
1.1328 + // Bits 95-64
1.1329 + TUint32 lockBit = KMMCCmdClassLockCard;
1.1330 +#ifdef __CARD0_NOT_LOCKABLE__
1.1331 + if (*Wins::CurrentPBusDevicePtr() == 0)
1.1332 + lockBit = 0;
1.1333 +#endif
1.1334 +#ifdef __CARD1_NOT_LOCKABLE__
1.1335 + if (*Wins::CurrentPBusDevicePtr() == 1)
1.1336 + lockBit = 0;
1.1337 +#endif
1.1338 + const TUint32 ccc =
1.1339 + KMMCCmdClassBasic | KMMCCmdClassBlockRead
1.1340 + | KMMCCmdClassBlockWrite | lockBit;
1.1341 + csd= (ccc<<20); /* CCC: classes 0, 2, 4, and 7 */
1.1342 + csd|= (0x9<<16); /* READ_BL_LEN: 512 bytes */
1.1343 + csd|= (0x0<<15); /* READ_BL_PARTIAL: No */
1.1344 + csd|= (0x0<<14); /* WRITE_BLK_MISALIGN: No */
1.1345 + csd|= (0x0<<13); /* READ_BLK_MISALIGN: No */
1.1346 + csd|= (0x0<<12); /* DSR_IMP: No DSR */
1.1347 + csd|= ((DWinsMMCStack::CSIZE>>10&3)<<8); /* C_SIZE: MMCSz Kb */
1.1348 + csd|= ((DWinsMMCStack::CSIZE>>2) & 0xFF); /* C_SIZE: MMCSz Kb */
1.1349 + TMMC::BigEndian4Bytes(&aResp[4],csd);
1.1350 + // Bits 63-32
1.1351 + csd= ((DWinsMMCStack::CSIZE&3)<<30); /* C_SIZE: MMCSz Kb */
1.1352 + csd|= (0x1<<27); /* VDD_R_CURR_MIN: 1mA */
1.1353 + csd|= (0x1<<24); /* VDD_R_CURR_MAX: 5mA */
1.1354 + csd|= (0x2<<21); /* VDD_W_CURR_MIN: 5mA */
1.1355 + csd|= (0x3<<18); /* VDD_W_CURR_MAX: 25mA */
1.1356 + csd|= ((DWinsMMCStack::CSIZE_MULT&0x07)<<15); /* C_SIZE_MULT: 0 */
1.1357 + csd|= (0x0<<10); /* SECTOR_SIZE: 1 write block */
1.1358 + csd|= (0x0<<5); /* ERASE_GRP_SIZE: 1 secotr */
1.1359 + csd|= (0x0); /* WP_GRP_SIZE: 1 erase group */
1.1360 + TMMC::BigEndian4Bytes(&aResp[8],csd);
1.1361 + // Bits 31-0
1.1362 + csd= (0x0<<31); /* WP_GRP_ENABLE: No */
1.1363 + csd|= (0x0<<29); /* DEFAULT_ECC: ? */
1.1364 + csd|= (0x3<<26); /* R2W_FACTOR: 8 */
1.1365 + csd|= (0x9<<22); /* WRITE_BL_LEN: 512 bytes */
1.1366 + csd|= (0x0<<21); /* WRITE_BL_PARTIAL: No */
1.1367 + csd|= (0x0<<15); /* FILE_FORMAT_GRP: Hard disk */
1.1368 + csd|= (0x0<<14); /* COPY: original */
1.1369 + csd|= (0x0<<13); /* PERM_WRITE_PROTECT: No */
1.1370 + csd|= (0x0<<12); /* TMP_WRITE_PROTECT: No */
1.1371 + csd|= (0x0<<10); /* FILE_FORMAT: Hard disk */
1.1372 + csd|= (0x0<<8); /* ECC: None */
1.1373 + csd|= (0x0<<1); /* CRC: ? */
1.1374 + csd|= (0x1); /* not used */
1.1375 + TMMC::BigEndian4Bytes(&aResp[12],csd);
1.1376 + }
1.1377 +
1.1378 +// ======== TWinsMMCPsu ========
1.1379 +
1.1380 +
1.1381 +DWinsMMCPsu::DWinsMMCPsu(TInt aVccNum, TInt aMcId)
1.1382 +//
1.1383 +// Constructor.
1.1384 +//
1.1385 + : DMMCPsu(aVccNum, aMcId)
1.1386 + {}
1.1387 +
1.1388 +TInt DWinsMMCPsu::DoCreate()
1.1389 +//
1.1390 +// Initialise the PSU
1.1391 +//
1.1392 + {
1.1393 + // Nothing to do
1.1394 + return KErrNone;
1.1395 + }
1.1396 +
1.1397 +void DWinsMMCPsu::DoSetState(TPBusPsuState aState)
1.1398 +//
1.1399 +// Turn on/off the PSU. If it is possible to adjust the output voltage on this
1.1400 +// PSU then retreive the required voltage level from TMMCPsu::iVoltageSetting
1.1401 +// (which is in OCR register format).
1.1402 +//
1.1403 + {
1.1404 +
1.1405 + switch (aState)
1.1406 + {
1.1407 + case EPsuOff:
1.1408 + break;
1.1409 + case EPsuOnFull:
1.1410 + break;
1.1411 + case EPsuOnCurLimit:
1.1412 + break;
1.1413 + }
1.1414 + }
1.1415 +
1.1416 +TInt DWinsMMCPsu::VoltageInMilliVolts()
1.1417 +//
1.1418 +// Return the level of the PSU (in mV) or -ve if error.
1.1419 +//
1.1420 + {
1.1421 +
1.1422 + return(0);
1.1423 + }
1.1424 +
1.1425 +void DWinsMMCPsu::DoCheckVoltage()
1.1426 +//
1.1427 +// Check the voltage level of the PSU is as expected. Returns either KErrNone, KErrGeneral
1.1428 +// to indicate the pass/fail state or KErrNotReady if the voltage check isn't complete.
1.1429 +//
1.1430 + {
1.1431 + ReceiveVoltageCheckResult(KErrNone);
1.1432 + }
1.1433 +
1.1434 +void DWinsMMCPsu::PsuInfo(TPBusPsuInfo &anInfo)
1.1435 +//
1.1436 +// Return machine info relating to the MMC PSU supply
1.1437 +//
1.1438 + {
1.1439 +
1.1440 + anInfo.iVoltageSupported=0x00040000; // 3.0V (OCR reg. format).
1.1441 + anInfo.iMaxCurrentInMicroAmps=0;
1.1442 + anInfo.iVoltCheckInterval=0;
1.1443 + anInfo.iVoltCheckMethod=EPsuChkComparator;
1.1444 + anInfo.iNotLockedTimeOut=0;
1.1445 + anInfo.iInactivityTimeOut=5;
1.1446 + }
1.1447 +