emulator/emulatorbsp/specific/mmc.cpp
changeset 0 cec860690d41
child 13 cb9d56c0e2af
equal deleted inserted replaced
-1:000000000000 0:cec860690d41
       
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // PP_MMC.CPP
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "plat_priv.h"
       
    19 #include <property.h>
       
    20 #include "variant.h"
       
    21 #include "variantmediadef.h"
       
    22 #include "mmci.h" 
       
    23 
       
    24 //#define  __CARD0_NOT_LOCKABLE__
       
    25 //#define  __CARD1_NOT_LOCKABLE__
       
    26 
       
    27 const TInt  KDiskSectorSize=512;
       
    28 
       
    29 TInt  DWinsMMCStack::TotalMDiskSize=0;		///< mmc card size for emulator
       
    30 TUint DWinsMMCStack::CSIZE=0;				///< mmc card size field
       
    31 TUint DWinsMMCStack::CSIZE_MULT=0;			///< mmc card size field
       
    32 
       
    33 TInt  DWinsMMCStack::TotalWinsMMC_CardSlots = KDefault_TotalWinsCardSlots; ///< total number of MMC card slots for the emulator
       
    34 TInt  DWinsMMCStack::TotalWinsMMC_Cards     = KDefault_TotalWinsCards;     ///< total number of MMC cards for the emulator
       
    35 
       
    36 
       
    37 const TUint32 KCsdStructure = 0x01;	/* CSD Version No 1.1 */
       
    38 const TUint32 KCsdSpecVers  = 0x03;	/* Version 3.1 */
       
    39 
       
    40 TInt MapLastErrorEpoc()
       
    41 //
       
    42 // Map an NT error to an Epoc/32 error.
       
    43 //
       
    44 	{
       
    45 	TInt res=KErrGeneral;
       
    46 	switch (GetLastError())
       
    47 		{
       
    48 		case ERROR_SHARING_VIOLATION : res=KErrAccessDenied; break;
       
    49 		case ERROR_LOCK_VIOLATION : res=KErrLocked; break;
       
    50 		case ERROR_FILE_NOT_FOUND: res=KErrNotFound; break;
       
    51 		case ERROR_PATH_NOT_FOUND: res=KErrPathNotFound; break;
       
    52 		case ERROR_ALREADY_EXISTS:
       
    53 		case ERROR_FILE_EXISTS:
       
    54 			res=KErrAlreadyExists;
       
    55 			break;
       
    56 		case ERROR_NOT_READY: res=KErrNotReady; break;
       
    57 		case ERROR_UNRECOGNIZED_VOLUME:
       
    58 		case ERROR_NOT_DOS_DISK:
       
    59 			res=KErrUnknown;
       
    60 			break;
       
    61 		case ERROR_UNRECOGNIZED_MEDIA: res=KErrCorrupt; break;
       
    62 		case ERROR_INVALID_NAME: res=KErrBadName; break;
       
    63 		case ERROR_NO_MORE_FILES: res=KErrEof; break;
       
    64 		}
       
    65 	return(res);
       
    66 	}
       
    67 
       
    68 TMMCErr MapLastErrorMmc()
       
    69 //
       
    70 // Map an NT error to a TMMCErr error.
       
    71 //
       
    72 	{
       
    73 	DWORD r=GetLastError();
       
    74 	TInt res=KErrGeneral;
       
    75 	switch (r)
       
    76 		{
       
    77 		case ERROR_SHARING_VIOLATION:
       
    78 		case ERROR_LOCK_VIOLATION:
       
    79 			res=KMMCErrLocked;			// KErrLocked
       
    80 			break;
       
    81 		case ERROR_FILE_NOT_FOUND:
       
    82 		case ERROR_PATH_NOT_FOUND:
       
    83 			res=KMMCErrNotFound;		// KErrNotFound
       
    84 			break;
       
    85 		case ERROR_ALREADY_EXISTS:
       
    86 		case ERROR_FILE_EXISTS:
       
    87 			res=KMMCErrAlreadyExists;	// KErrAlreadyExists
       
    88 			break;
       
    89 		case ERROR_NOT_READY: res=KMMCErrNoCard; break;
       
    90 		case ERROR_UNRECOGNIZED_VOLUME:
       
    91 		case ERROR_NOT_DOS_DISK:
       
    92 			res=KMMCErrGeneral;			// KErrGeneral
       
    93 			break;
       
    94 		case ERROR_UNRECOGNIZED_MEDIA:
       
    95 		case ERROR_INVALID_NAME:
       
    96 		case ERROR_NO_MORE_FILES:
       
    97 			res=KMMCErrResponseCRC; 	// KErrCorrupt
       
    98 			break;
       
    99 		}
       
   100 	return(res);
       
   101 	}
       
   102 
       
   103 
       
   104 void DWinsMMCStack::MachineInfo(TMMCMachineInfo& aMachineInfo)
       
   105 //
       
   106 // Return machine info relating to this MultiMediaCard Stack
       
   107 //
       
   108 	{
       
   109 	aMachineInfo.iTotalSockets=TotalWinsMMC_CardSlots;
       
   110 	aMachineInfo.iTotalMediaChanges=0;  		// Not used at present
       
   111 	aMachineInfo.iTotalPrimarySupplies=0;		// Not used at present
       
   112 
       
   113 	aMachineInfo.iFlags = TMMCMachineInfo::ESupportsDoubleBuffering;
       
   114     aMachineInfo.iBaseBusNumber=0;
       
   115 
       
   116 	__KTRACE_OPT(KPBUS1,Kern::Printf("<WinsMMC:MachineInfo"));
       
   117 	__KTRACE_OPT(KPBUS1,Kern::Printf(" %d stacks",aMachineInfo.iTotalSockets));
       
   118 
       
   119 	__ASSERT_DEBUG(aMachineInfo.iTotalSockets<=KMaxMMCardsPerStack,Panic(EWinsMMCBadMachineInfo));
       
   120 	}
       
   121 
       
   122 void DWinsMMCStack::AdjustPartialRead(
       
   123 	const TMMCard* aCard, TUint32 aStart, 
       
   124 #ifdef _DEBUG
       
   125 	TUint32 aEnd, 
       
   126 #else
       
   127 	TUint32 /*aEnd*/, 
       
   128 #endif
       
   129 	TUint32* aPhysStart, TUint32* aPhysEnd) const
       
   130 	{
       
   131 	const TUint32 blkLen = 1 << aCard->MaxReadBlLen();
       
   132 	const TUint32 blkMsk = blkLen - 1;
       
   133 #ifdef _DEBUG
       
   134 	__ASSERT_DEBUG(aCard->CSD().ReadBlPartial(), Panic(EWinsMMCAPRNotSupp));
       
   135 	__ASSERT_DEBUG(aEnd - aStart <= blkLen, Panic(EWinsMMCAPRRange));
       
   136 	__ASSERT_DEBUG((aEnd & ~blkMsk) > (aStart & ~blkMsk), Panic(EWinsMMCAPRBoundary));
       
   137 #endif
       
   138 
       
   139 	*aPhysStart = aStart & ~blkMsk;
       
   140 	*aPhysEnd = *aPhysStart + blkLen;
       
   141 	}
       
   142 
       
   143 void DWinsMMCStack::GetBufferInfo(TUint8** aMDBuf, TInt* aMDBufLen)
       
   144 	{
       
   145 	*aMDBuf = iMDBuf;
       
   146 	*aMDBufLen = iMDBufLen;
       
   147 	}
       
   148 
       
   149 void DWinsMMCStack::Panic(TWinsMMCPanic aPanic)
       
   150 	{
       
   151 	_LIT(KPncNm,"PBUS-MMC-WINS");
       
   152 	Kern::PanicCurrentThread(KPncNm,aPanic);
       
   153 	}
       
   154 
       
   155 DWinsMMCStack::DWinsMMCStack(TInt aBus, DMMCSocket* aSocket)
       
   156 	          :DMMCStack(aBus, aSocket)
       
   157 	{
       
   158 	
       
   159 //	iAddressedCard=0;
       
   160 //	iSecureArgDevAddr=0;
       
   161 //	iSecureArgTotalLength=0;
       
   162 //	iCMD42Failed=EFalse;
       
   163 	}
       
   164 
       
   165 
       
   166 /**
       
   167     Allocate cards.  Only called at bootup, so no cleanup if fails.
       
   168 */
       
   169 TInt DWinsMMCStack::Init()
       
   170 	{
       
   171 	 
       
   172     //-- try to read number of mmc cards and slots from epoc.ini file
       
   173     const TInt MmcSlots = Property::GetInt("MultiMediaCardSlots");
       
   174     const TInt MmcCards = Property::GetInt("MultiMediaCardsNum");
       
   175     
       
   176     if(MmcSlots == 0 && MmcCards == 0)
       
   177         {//-- parameters not specified, do nothing; static variables are initialized with default values
       
   178         }
       
   179     else
       
   180         {
       
   181         if((MmcSlots == 0 && MmcCards >0) || (MmcSlots > 0 && MmcCards ==0))
       
   182             {//-- only one of the parameters is specified. use it as "Cards quantity"
       
   183             TotalWinsMMC_Cards     = Max(MmcSlots, MmcCards); //-- chose non zero value
       
   184             TotalWinsMMC_CardSlots = Max(1, TotalWinsMMC_Cards-1);
       
   185             }
       
   186         else
       
   187             {//-- both parameters are specified
       
   188             TotalWinsMMC_Cards     = MmcCards;
       
   189             TotalWinsMMC_CardSlots = MmcSlots;
       
   190             }
       
   191     
       
   192         }//if(!MmcSlots && !MmcCards)
       
   193 
       
   194     TotalWinsMMC_Cards      = Min(TotalWinsMMC_Cards, KMax_TotalWinsCards);
       
   195     TotalWinsMMC_CardSlots  = Min(TotalWinsMMC_CardSlots, KMax_TotalWinsCardSlots);
       
   196 
       
   197     
       
   198     if((iCardArray = new TMMCardArray(this)) == NULL)
       
   199 		return KErrNoMemory;
       
   200 
       
   201 	TInt r=DMMCStack::Init();
       
   202 	if(r!=KErrNone)
       
   203 		return r;
       
   204 
       
   205 	DMediaChangeBase* pMCBase = MMCSocket()->iMediaChange;
       
   206 	static_cast<DWinsMMCMediaChange*>(pMCBase)->SetStackP(this);
       
   207 	Wins::SetMediaChangeCallBackPtr(DWinsMMCMediaChange::MediaChangeCallBack, (TAny*)pMCBase);
       
   208 
       
   209 	//
       
   210 	// Over time memory can become fragmented, and so it is not possible to
       
   211 	// allocate physically contiguous pages.  Therefore, the buffers for IO
       
   212 	// are allocated at startup.
       
   213 	//
       
   214 	// For the WINS implementation, fragmentation does not matter because
       
   215 	// DMA is not used.  The memory must still be allocated here so MEDMMC is
       
   216 	// able to use it.
       
   217 	//
       
   218 	// The constant calculations could be folded, but this illustrates how the
       
   219 	// values are derived.
       
   220 	//
       
   221 
       
   222 	// MMC only - values from Hitachi 16Mb card, datasheet HB288016MM1
       
   223 
       
   224 	// minor buffer must contain enough space for MBR or block
       
   225 	const TUint mmcBlkSzLog2 = 9;				// READ_BLK_LEN and WRITE_BLK_LEN
       
   226 	const TUint mmcBlkSz = 1 << mmcBlkSzLog2;
       
   227 	const TInt mmcMinorBufLen = Max(KDiskSectorSize, mmcBlkSz);
       
   228 
       
   229 	// There are 2 slots each with up to 2 media drivers; we allocate 8 blocks for each driver.
       
   230 	// It is the media drivers' responsibility to devide up the buffer space according 
       
   231 	// to which slot number is allocated to it (DMmcMediaDriverFlash::iCardNumber)
       
   232 	const TInt KMinMMCBlocksInBuffer = 16 * MMC0_NUMMEDIA;
       
   233 	const TInt mmcCchBufLen = KMinMMCBlocksInBuffer << mmcBlkSzLog2;
       
   234 
       
   235 	const TInt mmcTotalBufLen = mmcMinorBufLen + mmcCchBufLen;
       
   236 
       
   237 	const TInt totalBufLen = mmcTotalBufLen;
       
   238 
       
   239 	iMDBuf = reinterpret_cast<TUint8*>(Kern::Alloc(totalBufLen));
       
   240 	iMDBufLen = totalBufLen;
       
   241 
       
   242 	// setup card size parameters from epoc.ini
       
   243 	if (TotalMDiskSize==0)
       
   244 		{
       
   245 		// Static member variable TotalMDiskSize initialised to zero by default. Set 
       
   246 		// up static member variables TotalMDiskSize, CSIZE and CSIZE_MULT once and 
       
   247 		// once only. Use INI file setting if available. Else set to default, IMb.
       
   248 		TUint cardSize = Property::GetInt("MultiMediaCardSize");
       
   249 		if (cardSize)
       
   250 			{
       
   251 			// set values to match epoc.ini settings
       
   252 			SetupDiskParms(cardSize);
       
   253 			}		
       
   254 		else
       
   255 			{
       
   256 			// set default values for 1 MB drive
       
   257 			TotalMDiskSize=0x100000;
       
   258 			CSIZE=127;
       
   259 			CSIZE_MULT=2;
       
   260 			}
       
   261 		}
       
   262 
       
   263 	// Initialise each virtual card that will be used on this stack.
       
   264 	TInt i;
       
   265 	for (i=0 ; i<TotalWinsMMC_Cards; i++)
       
   266 		{
       
   267 		if ((r=SetupSimulatedCard(i))!=KErrNone)
       
   268 			return(r);
       
   269 		}
       
   270 
       
   271 	// initialize pointers to currently present cards
       
   272 
       
   273 	// Slot zero can toggle between no card; card 0 and card 1.  The current state is
       
   274 	// determined by *Kern::CurrentPBusDevicePtr() and toggled by pressing F4 when F5
       
   275 	// (door open) is held down.  Because this function is only executed at startup,
       
   276 	// assume start with card zero.
       
   277 	iCardInfo[0] = iCardPool[0];
       
   278 	for (i = 1; i < TotalWinsMMC_CardSlots; ++i)
       
   279 		{
       
   280 		iCardInfo[i]=iCardPool[i+1];
       
   281 		}
       
   282 
       
   283 	return(KErrNone);
       
   284 	}
       
   285 
       
   286 
       
   287 TInt DWinsMMCStack::CreateBinFileForCard(TInt aCardNum,HANDLE* aHandle,TBool aCreateNew)
       
   288 //
       
   289 // create .bin file in temp directory to contain media area of card.
       
   290 //
       
   291 	{
       
   292 	const char* emulatorPath = Property::GetString("EmulatorMediaPath");
       
   293 	if (!Emulator::CreateAllDirectories(emulatorPath))
       
   294 		return Emulator::LastError();
       
   295 
       
   296 	TBuf8<KMaxFileName> fn8(_L8(emulatorPath));
       
   297 	fn8.Append(_L8("MMCCRD"));
       
   298 	fn8.AppendNum(aCardNum);
       
   299 	fn8.Append(_L8("A.BIN"));
       
   300 	fn8.Append('\0');
       
   301 	*aHandle = CreateFileA(
       
   302 		(LPCSTR) fn8.Ptr(),							// LPCSTR lpFileName,
       
   303 		GENERIC_READ | GENERIC_WRITE,				// DWORD dwDesiredAccess
       
   304 		FILE_SHARE_READ | FILE_SHARE_WRITE,			// DWORD dwShareMode
       
   305 		NULL,										// LPSECURITY_ATTRIBUTES lpSecurityAttributes
       
   306 		aCreateNew ? CREATE_ALWAYS : OPEN_ALWAYS,	// DWORD dwCreationDisposition
       
   307 		FILE_FLAG_RANDOM_ACCESS,					// DWORD dwFlagsAndAttributes
       
   308 			NULL);									// HANDLE hTemplateFile
       
   309 	
       
   310 	TInt fileSize=GetFileSize(*aHandle,NULL);
       
   311 	if (fileSize>TotalMDiskSize)
       
   312 		//
       
   313 		// The Drive file already exists and size of emulated drive as configured in 
       
   314 		// epoc.ini has been reduced. Musn't corrupt the emulated drive so delete the 
       
   315 		// drive file and start from scratch. The emulated drive contents will be 
       
   316 		// erased.
       
   317 		//
       
   318 		{
       
   319 		CloseHandle(*aHandle);
       
   320 		DeleteFileA(
       
   321 			(LPCSTR) fn8.Ptr());						// LPCSTR lpFileName,			
       
   322 		*aHandle = CreateFileA(
       
   323 			(LPCSTR) fn8.Ptr(),							// LPCSTR lpFileName,
       
   324 			GENERIC_READ | GENERIC_WRITE,				// DWORD dwDesiredAccess
       
   325 			FILE_SHARE_READ | FILE_SHARE_WRITE,			// DWORD dwShareMode
       
   326 			NULL,										// LPSECURITY_ATTRIBUTES lpSecurityAttributes
       
   327 			aCreateNew ? CREATE_ALWAYS : OPEN_ALWAYS,	// DWORD dwCreationDisposition
       
   328 			FILE_FLAG_RANDOM_ACCESS,					// DWORD dwFlagsAndAttributes
       
   329 				NULL);									// HANDLE hTemplateFile
       
   330 		}
       
   331 
       
   332 	if (*aHandle==INVALID_HANDLE_VALUE)
       
   333 		return(MapLastErrorEpoc());
       
   334 
       
   335 	if (SetFilePointer(*aHandle,TotalMDiskSize,NULL,FILE_BEGIN)==0xffffffffu
       
   336 		||	! SetEndOfFile(*aHandle) )
       
   337 		{
       
   338 		CloseHandle(*aHandle);
       
   339 	    return(MapLastErrorEpoc());
       
   340 		}
       
   341 
       
   342 	return KErrNone;
       
   343 	}
       
   344 
       
   345 
       
   346 TInt DWinsMMCStack::SetupSimulatedCard(TInt aCardNum)
       
   347 //
       
   348 // allocate individual card with Win32 file.  Only called at bootup, so no cleanup if fails.
       
   349 //
       
   350 	{
       
   351 	TWinsCardInfo* cip = new TWinsCardInfo;
       
   352 	if (cip == 0)
       
   353 		return(KErrNoMemory);
       
   354 
       
   355 	TUint8 cid[KMMCCIDLength];
       
   356 	cid[0] = 'C';
       
   357 	cid[1] = 'I';
       
   358 	cid[2] = 'D';
       
   359 	cid[3] = TUint8('0' + aCardNum);
       
   360 	TInt j;
       
   361 	for (j = 4; j < KMMCCIDLength - 1; ++j)
       
   362 		cid[j] = 'c';
       
   363 	cid[KMMCCIDLength - 1] = '#';				// '#' = 0x23, bit zero must be 1
       
   364 	cip->iCID=cid;
       
   365 
       
   366 	cip->iPWD=new TMediaPassword;
       
   367 	if (!cip->iPWD)
       
   368 		{
       
   369 		delete cip;
       
   370 		return(KErrNoMemory);
       
   371 		}
       
   372 
       
   373 	cip->iState=ECardStateIdle;
       
   374 
       
   375 	HANDLE h=NULL;
       
   376 	TInt err;
       
   377 	if ( (err=CreateBinFileForCard(aCardNum,&h))!=KErrNone )
       
   378 		{
       
   379 		delete cip;
       
   380 		return(err);
       
   381 		}
       
   382 	cip->iWinHandle=h;
       
   383 	iCardPool[aCardNum]=cip;
       
   384 	return(KErrNone);
       
   385 	}
       
   386 
       
   387 void DWinsMMCStack::SetBusConfigDefaults(TMMCBusConfig& aConfig, TUint aClock)
       
   388 //
       
   389 // Fills BusConfig structure with default values
       
   390 //
       
   391 	{
       
   392 	const TUint KWinsMaxHwInterfaceClk=104000;
       
   393 	const TUint KWinsResponseTimeOut=6400;
       
   394 	const TUint KWinsDataTimeOut=40000;
       
   395 	const TUint KWinsBusyTimeOut=200000;
       
   396 
       
   397 	aConfig.iBusClock = (aClock > KWinsMaxHwInterfaceClk) ? KWinsMaxHwInterfaceClk : aClock;
       
   398 	aConfig.iResponseTimeOut=KWinsResponseTimeOut;
       
   399 	aConfig.iDataTimeOut=KWinsDataTimeOut;
       
   400 	aConfig.iBusyTimeOut=KWinsBusyTimeOut;
       
   401 	}
       
   402 
       
   403 void DWinsMMCStack::InitClockOff()
       
   404 //
       
   405 // Switch of the identification mode clock and enable the data transfer mode
       
   406 // clock instead.
       
   407 //
       
   408 	{
       
   409 	// empty.
       
   410 	}
       
   411 
       
   412 void DWinsMMCStack::ASSPReset()
       
   413 //
       
   414 // Stop all activities on the host stack
       
   415 //
       
   416 	{
       
   417 	// empty.
       
   418 	}
       
   419 
       
   420 void DWinsMMCStack::ASSPDisengage()
       
   421 //
       
   422 // Forced release of all ASSP resources
       
   423 //
       
   424 	{
       
   425 	}
       
   426 
       
   427 void DWinsMMCStack::DoPowerDown()
       
   428 //
       
   429 // Power down the bus
       
   430 //
       
   431 	{
       
   432 	// Change the state of all virtual cards present to Idle
       
   433 	for (TInt i=0 ; i<TotalWinsMMC_CardSlots ; i++)
       
   434 		iCardInfo[i]->iState=ECardStateIdle;
       
   435 	}
       
   436 
       
   437 
       
   438 LOCAL_C TInt SetMediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,const TDesC8& aPasswd)
       
   439 // 
       
   440 // Set the password for local drive 'aLocalDrive', card number 'aCardNum' to 'aPasswd' - as an
       
   441 // environment variable. Note that the card number is only relevant where the emulated drive
       
   442 // supports card hot-swapping (i.e. F4 whilst F5 is held down).
       
   443 //
       
   444 	{
       
   445 	// Setup the appropriate environment variable string '_EPOC_LocDrv_<locDrvNum>_PWORD_<cardNum>'
       
   446 	TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
       
   447 
       
   448 	envVar[13]=(TUint16)('0'+aSocketNum);
       
   449 	envVar[21]=(TUint16)('0'+aCardNum);
       
   450 	
       
   451 	// Setup the new value of the environment variable
       
   452 	TUint16	envVal[100];
       
   453 	TInt len=aPasswd.Length();
       
   454 
       
   455 	// the password may be empty if a card's password is cleared
       
   456 	if (len>(100-1))
       
   457 		return(KErrArgument);
       
   458 	memcpy(&envVal[0],reinterpret_cast<const TUint16 *>(aPasswd.Ptr()),len);
       
   459 	envVal[len>>1]='\0';
       
   460 
       
   461 	// Now set the new value for the environment variable
       
   462 	if (SetEnvironmentVariable(envVar,&envVal[0]))
       
   463 		return(KErrNone);
       
   464 
       
   465 	return KErrGeneral;
       
   466 	}
       
   467 
       
   468 LOCAL_C TInt MediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,TDes8& aPasswd)
       
   469 // 
       
   470 // Get the password for local drive 'aLocalDrive', card number 'aCardNum' into 'aPasswd' - from
       
   471 // an environment variable. Note that the card number is only relevant where the emulated drive
       
   472 // supports card hot-swapping (i.e. F4 whilst F5 is held down).
       
   473 //
       
   474 	{
       
   475 	TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
       
   476 
       
   477 	envVar[13]=(TUint16)('0'+aSocketNum);
       
   478 	envVar[21]=(TUint16)('0'+aCardNum);
       
   479 	
       
   480 	TUint16 envVal[100];	// To hold the value of the retreived environment variable
       
   481 	
       
   482 	DWORD len=GetEnvironmentVariable(envVar,&envVal[0],100);
       
   483 	if (len>(TUint)100)
       
   484 		return(KErrGeneral);
       
   485 	if (len)
       
   486 		{
       
   487 		// Found the requested environment variable so there is a password for this local drive / card. 
       
   488 		if ((len<<1)<=KMaxMediaPassword)
       
   489 			{
       
   490 			aPasswd.FillZ(KMaxMediaPassword);
       
   491 			aPasswd.Zero();
       
   492 			aPasswd.Copy(reinterpret_cast<TUint8*>(&envVal[0]),len<<1);
       
   493 			return(KErrNone);	
       
   494 			}
       
   495 		else	
       
   496 			return(KErrGeneral);	
       
   497 		}
       
   498 
       
   499 	return(KErrNotFound);
       
   500 	}
       
   501 
       
   502 TMMCErr DWinsMMCStack::DoPowerUpSM()
       
   503 //
       
   504 //	State Machine functions implemented in ASSP layer
       
   505 //
       
   506 	{
       
   507 	enum states
       
   508 		{
       
   509 		EStBegin=0,
       
   510 		EStEnd
       
   511 		};
       
   512 
       
   513 	SMF_BEGIN
       
   514 
       
   515 	__KTRACE_OPT(KPBUS1, Kern::Printf("DoPowerUpSM: BEGIN"));
       
   516 
       
   517 	if( MMCSocket()->iVcc->SetState(EPsuOnCurLimit) != KErrNone )
       
   518 		return( KMMCErrHardware );
       
   519 
       
   520 	for (TInt i=0 ; i<TotalWinsMMC_CardSlots ; i++)
       
   521 		{
       
   522 		// Attempt to retrieve a password for this card from environment settings (as long as this
       
   523 		// isn't card0 and we are simulating this is not present)
       
   524 		TInt cardNum=(i==0) ? *Wins::CurrentPBusDevicePtr() : i;
       
   525 		if (cardNum>=0 && MediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[i]->iPWD))==KErrNone)
       
   526 			{
       
   527 			// Card has a password so lock it automatically on power up.		
       
   528 			iCardInfo[i]->iIsLocked=(iCardInfo[i]->iPWD->Length() > 0);
       
   529 			}
       
   530 		else	
       
   531 			iCardInfo[i]->iIsLocked=EFalse;
       
   532 			
       
   533 		iCardInfo[i]->iRCA=0x0001;		// Default RCA - spec 2.2, s4.2.1, 5.4
       
   534 		}
       
   535 
       
   536 		ReportPowerUp();
       
   537 
       
   538 	SMF_END
       
   539 	}
       
   540 
       
   541 TMMCErr DWinsMMCStack::InitClockOnSM()
       
   542 //
       
   543 // Switch on the identification mode clock
       
   544 //
       
   545 	{
       
   546 	enum states
       
   547 		{
       
   548 		EStBegin=0,
       
   549 		EStEnd
       
   550 		};
       
   551 	SMF_BEGIN
       
   552 
       
   553 	SMF_END
       
   554 	}
       
   555 
       
   556 TMMCErr DWinsMMCStack::ModifyCardCapabilitySM()
       
   557 //
       
   558 // This function provides a chance to modify the capability of paticular cards.
       
   559 // Licensee may overide this function to modify certain card's capability as needed.
       
   560 // A state machine is needed in derived function and function of base class should be
       
   561 // called in order to act more generic behaviour.
       
   562 //
       
   563     {
       
   564 		enum states
       
   565 			{
       
   566 			EStBegin=0,
       
   567             EStDone,
       
   568 			EStEnd
       
   569 			};
       
   570 
       
   571     SMF_BEGIN
       
   572 
       
   573         SMF_INVOKES( DMMCStack::BaseModifyCardCapabilitySMST, EStDone )
       
   574 
       
   575     SMF_STATE(EStDone)
       
   576 
       
   577     SMF_END
       
   578     }
       
   579 
       
   580 TInt DWinsMMCStack::GetTargetSlotNumber(TBool anRCASupplied,const TRCA& anRCA)
       
   581 // 
       
   582 // Attempt to determine the slot number of the target card. If the received command
       
   583 // contained an RCA then 'anRCASupplied' will be ETrue - in which case, 'anRCA'
       
   584 // contains the RCA in question.
       
   585 // 
       
   586 	{
       
   587 	TInt selCardIdx = KBroadcastToAllCards;
       
   588 
       
   589 	// if an RCA was supplied, then work out which card slot it corresponds to
       
   590 	if (anRCASupplied)
       
   591 		{
       
   592 		for (TInt i = 0 ; i < TotalWinsMMC_CardSlots ; ++i)
       
   593 			{
       
   594 			if (iCardInfo[i]->iRCA==anRCA)
       
   595 				{
       
   596 				selCardIdx=i;
       
   597 				break;
       
   598 				}
       
   599 			}
       
   600 		}
       
   601 	// else search for currently selected card
       
   602 	else
       
   603 		{
       
   604 		for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
       
   605 			{
       
   606 			if (iCardInfo[i]->iState == ECardStateTran)
       
   607 				{
       
   608 				selCardIdx = i;
       
   609 				break;
       
   610 				}
       
   611 			}
       
   612 		}
       
   613 
       
   614 	return(selCardIdx);
       
   615 	}
       
   616 
       
   617 TMMCErr DWinsMMCStack::IssueMMCCommandSM()
       
   618 //
       
   619 // Top level ASSP command executor
       
   620 //
       
   621 	{
       
   622 	enum states
       
   623 		{
       
   624 		EStBegin=0,
       
   625 		EStDoubleBuffer,
       
   626 		EStCommandDone,
       
   627 		EStEnd
       
   628 		};
       
   629 
       
   630 	TMMCCommandDesc& cmd = Command();
       
   631 
       
   632 	TRCA tgtRCA=0;
       
   633 	TBool supRCA=EFalse;
       
   634 	// Record the RCA if it is embedded in the argument [31:16].
       
   635 	if (cmd.iCommand == ECmdSetRelativeAddr	||	cmd.iCommand == ECmdSelectCard
       
   636 	||	cmd.iCommand == ECmdSendCSD			||	cmd.iCommand == ECmdSendCID
       
   637 	||	cmd.iCommand == ECmdSendStatus		||	cmd.iCommand == ECmdGoInactiveState
       
   638 	||	cmd.iCommand == ECmdFastIO 			||  cmd.iCommand == ECmdAppCmd )
       
   639 		{
       
   640 		supRCA=ETrue;
       
   641 		tgtRCA=TUint16(cmd.iArgument >> 16);
       
   642 		}
       
   643 
       
   644 	// Attempt to determine the target card using supplied RCA
       
   645 	TInt selCardIdx=GetTargetSlotNumber(supRCA,tgtRCA);
       
   646 	
       
   647 	// Simulation of card swapping (i.e. F4/F5) is performed on slot 0. If this is currently
       
   648 	// set to simulate no card present and the issued command is targetted specifically at the
       
   649 	// card in slot 0 (i.e. not a broadcast command) then timeout.
       
   650 	if (selCardIdx==0 && *Wins::CurrentPBusDevicePtr() < 0)
       
   651 		return(KMMCErrResponseTimeOut);
       
   652 	 
       
   653 	// If an RCA was supplied but didn't coincide with the RCAs of any cards present 
       
   654 	// then timeout (Ignore SET_RCA and APP_CMD as these are sent before RCAs are assigned).
       
   655 	if (supRCA && selCardIdx==KBroadcastToAllCards &&
       
   656 		cmd.iCommand != ECmdSetRelativeAddr && cmd.iCommand != ECmdAppCmd)
       
   657 		return(KMMCErrResponseTimeOut);
       
   658 
       
   659 	HANDLE winHandle=NULL;
       
   660 
       
   661 	// CMD42 is a data transfer command.  That means the R1 response that it returns
       
   662 	// immediately is the state it is in on receiving the data block, and not after
       
   663 	// processing it.  If the data block is invalid then LOCK_UNLOCK_FAILED will be
       
   664 	// set in the R1 response which is sent in reply to the next command.
       
   665 
       
   666 	TBool nextCMD42Failed = EFalse;
       
   667 	TBool lock_unlock_failed=EFalse;
       
   668 
       
   669 	// When the card is locked, it will only respond to basic command class (0) and
       
   670 	// lock card command class (7).  An exception is CMD16.  This is sent before CMD42,
       
   671 	// but is classified (MMC Spec 23.2, table 5) as belonging to classes 2 and 4.
       
   672 	// For data transfer commands, LOCK_UNLOCK_FAIL is set in response to the following
       
   673 	const TMMCCommandEnum origCmd(cmd.iCommand);
       
   674 	if (	selCardIdx != KBroadcastToAllCards
       
   675 		&&	iCardInfo[selCardIdx]->iIsLocked			// If locked and not in CCC 0 or 7 then skip
       
   676 		&&	(	((cmd.iSpec.iCommandClass & (KMMCCmdClassBasic | KMMCCmdClassLockCard)) == 0)
       
   677 			&&	cmd.iCommand != ECmdSetBlockLen ) )
       
   678 		{
       
   679 		lock_unlock_failed = ETrue;				// try to access locked card
       
   680 		cmd.iCommand = TMMCCommandEnum(-1);		// skip command processing
       
   681 		}
       
   682 
       
   683 	SMF_BEGIN
       
   684 
       
   685 	TBool rto = EFalse;							// response timeout
       
   686 	switch (cmd.iCommand)
       
   687 		{
       
   688 		case ECmdGoIdleState:	// CMD0
       
   689 			{
       
   690 			for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
       
   691 				iCardInfo[i]->iState = ECardStateIdle;
       
   692 			}
       
   693 			break;
       
   694 
       
   695 		case ECmdSendOpCond:	// CMD1
       
   696 			{
       
   697 			for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
       
   698 				iCardInfo[i]->iState = ECardStateReady;
       
   699 
       
   700 			// bit32 is set to indicate cards are not still powering up
       
   701 			TUint32 r3 = KMMCWinsCardOCRValue | KMMCOCRBusy;
       
   702 			TMMC::BigEndian4Bytes(cmd.iResponse, r3);
       
   703 			}
       
   704 			break;
       
   705 
       
   706 		case ECmdAllSendCID:	// CMD2
       
   707 			{
       
   708 			TInt idx = FindAnyCardInStack(ECardStateReady);
       
   709 
       
   710 			if (idx == -1)
       
   711 				rto = ETrue;
       
   712 			else
       
   713 				{
       
   714 				iCardInfo[idx]->iCID.Copy(cmd.iResponse);
       
   715 				iCardInfo[idx]->iState = ECardStateIdent;
       
   716 				}
       
   717 			}
       
   718 			break;
       
   719 
       
   720 		case ECmdSetRelativeAddr:	// CMD3
       
   721 			{
       
   722 			TInt idx = FindOneCardInStack(ECardStateIdent);
       
   723 			iCardInfo[idx]->iRCA = tgtRCA;
       
   724 			iCardInfo[idx]->iState=ECardStateStby;
       
   725 			selCardIdx = idx;					// set R1 response at end
       
   726 			}
       
   727 			break;
       
   728 
       
   729 		case ECmdSelectCard:		// CMD7
       
   730 			{
       
   731 			// switch to broadcast mode so the currently selected and new cards
       
   732 			// receive the command simultaneously.
       
   733 
       
   734 			TInt idx = FindAnyCardInStack(ECardStateTran);
       
   735 			if (idx != -1)
       
   736 				iCardInfo[idx]->iState = ECardStateStby;
       
   737 			iCardInfo[selCardIdx]->iState = ECardStateTran;
       
   738 			}
       
   739 			break;
       
   740 
       
   741 		case ECmdSendStatus:
       
   742 			// R1 response so status return as for any other R1 command.
       
   743 			break;
       
   744 
       
   745 		case ECmdReadSingleBlock:
       
   746 		case ECmdReadMultipleBlock:
       
   747 			{
       
   748 			winHandle=iCardInfo[selCardIdx]->iWinHandle;
       
   749 
       
   750 			if ( cmd.iSpec.iUseStopTransmission && cmd.iBlockLength >= cmd.iTotalLength)
       
   751 				return( KMMCErrNotSupported );
       
   752 
       
   753     		TMMCErr err;
       
   754 			TInt pos = cmd.iArgument;
       
   755     		if (SetFilePointer(winHandle,pos,NULL,FILE_BEGIN)==0xffffffffu)
       
   756         		err=MapLastErrorMmc();
       
   757     		else
       
   758         		{
       
   759 				iBytesToTransfer = cmd.BufferLength();
       
   760 				err = ReadWriteData(selCardIdx, cmd.iDataMemoryP, iBytesToTransfer, cmd.iSpec.iDirection);
       
   761 				if(err == KMMCErrNone)
       
   762 					{
       
   763 					Session().RequestMoreData();
       
   764 					SMF_WAITS(EStDoubleBuffer);
       
   765 					}
       
   766 				}
       
   767 			if (err!=KMMCErrNone)
       
   768 				return(err);
       
   769 			}
       
   770 			break;
       
   771 
       
   772 		// ------------------------------------------------------------------
       
   773 		case ECmdWriteBlock:
       
   774 		case ECmdWriteMultipleBlock:
       
   775 			{
       
   776 			HANDLE h = iCardInfo[selCardIdx]->iWinHandle;
       
   777 
       
   778     		TMMCErr err;
       
   779 			TInt pos = cmd.iArgument;
       
   780     		if (SetFilePointer(h, pos, NULL, FILE_BEGIN)==0xffffffffu)
       
   781         		err = MapLastErrorMmc();
       
   782     		else
       
   783         		{
       
   784 				iBytesToTransfer = cmd.BufferLength();
       
   785 				err = ReadWriteData(selCardIdx, cmd.iDataMemoryP, iBytesToTransfer, cmd.iSpec.iDirection);
       
   786 				if(err == KMMCErrNone)
       
   787 					{
       
   788 					Session().RequestMoreData();
       
   789 					SMF_WAITS(EStDoubleBuffer);
       
   790 					}
       
   791 				}
       
   792 
       
   793 			if (err!=KMMCErrNone)
       
   794 				return(err);
       
   795 			}
       
   796 			break;
       
   797 
       
   798 		case ECmdAppCmd:
       
   799 			rto = ETrue;
       
   800 			break;
       
   801 
       
   802 		case ECmdSendCSD:
       
   803 			{
       
   804 			iCardInfo[selCardIdx]->GetCSD(cmd.iResponse);
       
   805 			break;
       
   806 			}
       
   807 
       
   808 		// ------------------------------------------------------------------
       
   809 		case ECmdLockUnlock:
       
   810 			// in EPOC, Lock() does not actually lock the card.  It just sets the
       
   811 			// password.  This means that the card is still accessible to the user,
       
   812 			// but must be unlocked the next time it is powered up.
       
   813 
       
   814 			// a real card will transiently go into rcv and prg state while processing
       
   815 			// this command.  When finished, it will fall back into tran state.
       
   816 			// The R1 response is sent immediately after CMD42.  CIMReadWriteBlocksSM()
       
   817 			// sends CMD13 to find out whether or not LOCK_UNLOCK_FAIL was set.
       
   818 
       
   819 			// the asserts in this case protect against invalid data being sent from the
       
   820 			// media driver.  A real card would fail these corrupt data blocks.
       
   821 
       
   822 			{
       
   823 #ifdef __CARD0_NOT_LOCKABLE__
       
   824 			if (*Wins::CurrentPBusDevicePtr() == 0)
       
   825 				return KMMCErrNotSupported;
       
   826 #endif
       
   827 #ifdef __CARD1_NOT_LOCKABLE__
       
   828 			if (*Wins::CurrentPBusDevicePtr() == 1)
       
   829 				return KMMCErrNotSupported;
       
   830 #endif
       
   831 			const TInt8 cmd_byte(*cmd.iDataMemoryP);
       
   832 			__ASSERT_DEBUG(										// ensure not CLR_PWD && SET_PWD
       
   833 				!((cmd_byte & KMMCLockUnlockClrPwd) && (cmd_byte & KMMCLockUnlockSetPwd)),
       
   834 				DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
       
   835 			
       
   836 			__ASSERT_DEBUG(										// ensure not FORCE_ERASE with CLR_PWD or SET_PWD
       
   837 				!((cmd_byte & KMMCLockUnlockErase) && (cmd_byte & (KMMCLockUnlockSetPwd | KMMCLockUnlockClrPwd))),
       
   838 				DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
       
   839 			
       
   840 			__ASSERT_DEBUG(										// not actually lock a card while setting the password
       
   841 				((cmd_byte & (KMMCLockUnlockLockUnlock | KMMCLockUnlockSetPwd)) != (KMMCLockUnlockLockUnlock | KMMCLockUnlockSetPwd)),
       
   842 				DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCLockAttempt) );
       
   843 
       
   844 			if (cmd_byte & KMMCLockUnlockErase)								// Forced Erase of a locked card
       
   845 				{
       
   846 				if (iCardInfo[selCardIdx]->iIsLocked)						// Forced erase when locked
       
   847 					{
       
   848 					iCardInfo[selCardIdx]->iPWD->Zero();					// Remove the password
       
   849 					iCardInfo[selCardIdx]->iIsLocked = EFalse;
       
   850 					nextCMD42Failed = EFalse;
       
   851 					
       
   852 					TInt cardNum = (selCardIdx==0) ? *Wins::CurrentPBusDevicePtr() : selCardIdx;
       
   853 					SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[selCardIdx]->iPWD));
       
   854 
       
   855 					// Erase then entire contents of the emulated drive
       
   856 					HANDLE handle = iCardInfo[selCardIdx]->iWinHandle;
       
   857 					CloseHandle(handle);
       
   858 					iCardInfo[selCardIdx]->iWinHandle = NULL;
       
   859 					if(CreateBinFileForCard(selCardIdx, &handle, ETrue) != KErrNone)
       
   860 						return(MapLastErrorMmc());
       
   861 					iCardInfo[selCardIdx]->iWinHandle = handle;
       
   862 					}
       
   863 				else														// Forced erase when unlocked (illegal)
       
   864 					{
       
   865 					nextCMD42Failed = ETrue;
       
   866 					}
       
   867 				}
       
   868 			else
       
   869 				{
       
   870 				const TInt8 pwd_len = *(cmd.iDataMemoryP + 1);
       
   871 				const TPtrC8 pwd(cmd.iDataMemoryP + 2, pwd_len);
       
   872 
       
   873 				if ((cmd_byte & KMMCLockUnlockClrPwd) != 0)			// CLR_PWD == 1
       
   874 					{
       
   875 					__ASSERT_DEBUG(
       
   876 						pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
       
   877 						DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand));
       
   878 
       
   879 					if (iCardInfo[selCardIdx]->iIsLocked)						// clear when locked
       
   880 						nextCMD42Failed = ETrue;
       
   881 					else														// clear when unlocked
       
   882 						{
       
   883 						if (iCardInfo[selCardIdx]->iPWD->Compare(pwd) != 0)		// clear when unlocked with wrong password
       
   884 							{
       
   885 							nextCMD42Failed = ETrue;
       
   886 							lock_unlock_failed = ETrue;
       
   887 							}
       
   888 						else													// clear when unlocked with right password
       
   889 							{
       
   890 							// Clear from password store 
       
   891 							iCardInfo[selCardIdx]->iPWD->Zero();
       
   892 							iCardInfo[selCardIdx]->iIsLocked = EFalse;
       
   893 							nextCMD42Failed = EFalse;
       
   894 							
       
   895 							// Clear from environment settings
       
   896 							TInt cardNum=(selCardIdx==0) ? *Wins::CurrentPBusDevicePtr() : selCardIdx; // Can't be -1 at this stage
       
   897 							SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[selCardIdx]->iPWD));
       
   898 							}
       
   899 						}
       
   900 					}
       
   901 				else if ((cmd_byte & KMMCLockUnlockSetPwd) == 0)	// SET_PWD == 0: unlock
       
   902 					{
       
   903 					__ASSERT_DEBUG(
       
   904 						pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
       
   905 						DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
       
   906 					
       
   907 					if (! iCardInfo[selCardIdx]->iIsLocked)						// unlock when unlocked
       
   908 						nextCMD42Failed = ETrue;
       
   909 					else
       
   910 						{
       
   911 						if (iCardInfo[selCardIdx]->iPWD->Compare(pwd) != 0)		// unlock when locked with wrong password
       
   912 							{
       
   913 							nextCMD42Failed = ETrue;
       
   914 							lock_unlock_failed = ETrue;
       
   915 							}
       
   916 						else													// unlock when locked with right password
       
   917 							{
       
   918 							iCardInfo[selCardIdx]->iIsLocked = EFalse;
       
   919 							nextCMD42Failed = EFalse;
       
   920 							}
       
   921 						}
       
   922 					}
       
   923 				else  if ((cmd_byte & KMMCLockUnlockSetPwd) == KMMCLockUnlockSetPwd)	// SET_PWD == 1
       
   924 					{
       
   925 					__ASSERT_DEBUG(
       
   926 						cmd_byte & KMMCLockUnlockSetPwd,
       
   927 						DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
       
   928 
       
   929 					// if pwd_len < iCardInfo[selCardIdx]->iPWD->Length() then data block must be invalid.
       
   930 					// This can be caused by bad user input rather than inaccurate formation.
       
   931 					if (!(	pwd_len >= iCardInfo[selCardIdx]->iPWD->Length()
       
   932 						&&	pwd_len <= iCardInfo[selCardIdx]->iPWD->Length() + KMaxMediaPassword ))
       
   933 						{
       
   934 						nextCMD42Failed = ETrue;
       
   935 						}
       
   936 					else
       
   937 						{
       
   938 						TUint16 env_Var[]=L"_EPOC_PWD_LEN";
       
   939 						TUint16 env_Val[2];
       
   940 						TInt r=GetEnvironmentVariable(env_Var,&env_Val[0],2);
       
   941 						r=r;//This code is added to suppress WINS warnings
       
   942 						__ASSERT_DEBUG(r!=0,Kern::PanicCurrentThread(_L("PBUS-MMC-WINS-GETENV"),0));			
       
   943 						const TInt old_pwd_len=env_Val[0]-1;
       
   944 						TPtrC8 old_pwd(cmd.iDataMemoryP + 2, old_pwd_len);
       
   945 						TPtrC8 new_pwd(cmd.iDataMemoryP + 2 + old_pwd_len, pwd_len - old_pwd_len);
       
   946 						
       
   947 						// card must not be locked and supplied current password must be correct
       
   948 						if (iCardInfo[selCardIdx]->iIsLocked || iCardInfo[selCardIdx]->iPWD->Compare(old_pwd) != 0)
       
   949 							{
       
   950 							nextCMD42Failed = ETrue;
       
   951 							lock_unlock_failed = ETrue;
       
   952 							}
       
   953 						else
       
   954 							{
       
   955 							// Set in password store
       
   956 							iCardInfo[selCardIdx]->iPWD->Copy(new_pwd);
       
   957 							nextCMD42Failed = EFalse;
       
   958 							
       
   959 							// Set in environment settings
       
   960 							TInt cardNum=(selCardIdx==0) ? *Wins::CurrentPBusDevicePtr() : selCardIdx; // Can't be -1 at this stage
       
   961 							SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[selCardIdx]->iPWD));
       
   962 							}
       
   963 						}
       
   964 					}
       
   965 				else  if ((cmd_byte & KMMCLockUnlockLockUnlock) == KMMCLockUnlockLockUnlock)
       
   966 					{
       
   967 					__ASSERT_DEBUG(
       
   968 						pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
       
   969 						DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCCorruptCommand) );
       
   970 					
       
   971 					if (iCardInfo[selCardIdx]->iIsLocked)						// lock when locked
       
   972 						nextCMD42Failed = ETrue;
       
   973 					else
       
   974 						{
       
   975 						if (iCardInfo[selCardIdx]->iPWD->Compare(pwd) != 0)		// lock with wrong password
       
   976 							{
       
   977 							nextCMD42Failed = ETrue;
       
   978 							lock_unlock_failed = ETrue;
       
   979 							}
       
   980 						else													// lock with right password
       
   981 							{
       
   982 							iCardInfo[selCardIdx]->iIsLocked = ETrue;
       
   983 							nextCMD42Failed = EFalse;
       
   984 							}
       
   985 						}
       
   986 					}
       
   987 				else
       
   988 					{
       
   989 					__ASSERT_DEBUG(EFalse, DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCLockAttempt) );
       
   990 					}
       
   991 				}
       
   992 			}	// case ECmdLockUnlock
       
   993 			break;
       
   994 		
       
   995 		case ECmdSetBlockCount:		
       
   996 			{
       
   997 			// Only supported in version 3.1
       
   998 			if(Session().iCardP->CSD().SpecVers() != 3)
       
   999 				{
       
  1000 				return(KMMCErrNotSupported);
       
  1001 				}
       
  1002 			}
       
  1003 			break;
       
  1004 			
       
  1005 		// ------------------------------------------------------------------
       
  1006 		default:
       
  1007 			break;
       
  1008 		}
       
  1009 
       
  1010 		if (rto)
       
  1011 			{
       
  1012 			return(KMMCErrResponseTimeOut);
       
  1013 			}
       
  1014 
       
  1015 	// drop through to command done...
       
  1016 
       
  1017 	SMF_STATE(EStCommandDone)
       
  1018 
       
  1019 		cmd.iCommand = origCmd;
       
  1020 		// If this is an R1 or R1b response type command then return card status as a response
       
  1021 		if (	selCardIdx != KBroadcastToAllCards
       
  1022 			&&	(cmd.iSpec.iResponseType==ERespTypeR1 || cmd.iSpec.iResponseType==ERespTypeR1B) )
       
  1023 			{
       
  1024 			TUint32 resp(
       
  1025 					iCardInfo[selCardIdx]->iState
       
  1026 				|	((iCardInfo[selCardIdx]->iIsLocked ? 1 : 0) << 25)
       
  1027 				|	((lock_unlock_failed ? 1 : 0) << 24) );
       
  1028 
       
  1029 			if (iCMD42Failed)								// previous CMD42
       
  1030 				{
       
  1031 				resp |= KMMCStatErrLockUnlock;
       
  1032 				nextCMD42Failed = EFalse;
       
  1033 				}
       
  1034 			iCMD42Failed = nextCMD42Failed;
       
  1035 			TMMC::BigEndian4Bytes(&cmd.iResponse[0],resp); // Ignore bits 47-40
       
  1036 			}
       
  1037 
       
  1038 		SMF_GOTOS(EStEnd);
       
  1039 
       
  1040 	SMF_STATE(EStDoubleBuffer)
       
  1041 
       
  1042 		cmd.iBytesDone += iBytesToTransfer;
       
  1043 
       
  1044         if(cmd.iBytesDone < cmd.iTotalLength)
       
  1045 			{
       
  1046 			iBytesToTransfer = cmd.BufferLength();
       
  1047 			TMMCErr err = ReadWriteData(selCardIdx, cmd.iDataMemoryP, iBytesToTransfer, cmd.iSpec.iDirection);
       
  1048 			if(err == KMMCErrNone)
       
  1049 				{
       
  1050 				Session().RequestMoreData();
       
  1051 				SMF_WAITS(EStDoubleBuffer);
       
  1052 				}
       
  1053 			else
       
  1054 				{
       
  1055 				return(err);
       
  1056 				}
       
  1057 			}
       
  1058 		else
       
  1059 			{
       
  1060 			SMF_GOTOS(EStCommandDone);
       
  1061 			}
       
  1062 
       
  1063 	SMF_END
       
  1064 	}
       
  1065 
       
  1066 
       
  1067 TMMCErr DWinsMMCStack::ReadWriteData(TInt aCardIdx, TUint8* aDataP, TUint32 aLength, TMMCCmdDirEnum aDir)
       
  1068 	{
       
  1069 	TMMCErr err = KMMCErrNone;
       
  1070 
       
  1071 	HANDLE h = iCardInfo[aCardIdx]->iWinHandle;
       
  1072 
       
  1073 	DWORD res;
       
  1074 	TBool success;
       
  1075 	
       
  1076 	if(aDir == EDirWrite)
       
  1077 		{
       
  1078 		success = WriteFile(h, (LPCVOID)aDataP, aLength, &res, NULL);
       
  1079 		}
       
  1080 	else
       
  1081 		{
       
  1082 		success = ReadFile(h, (LPVOID)aDataP, aLength, &res, NULL);
       
  1083 		}
       
  1084 
       
  1085 	if (!success)
       
  1086 		{
       
  1087 		err=MapLastErrorMmc();
       
  1088 		}
       
  1089 	else if (res != (DWORD)aLength)
       
  1090 		{
       
  1091 		err=KMMCErrGeneral;
       
  1092 		}
       
  1093 
       
  1094 	return(err);
       
  1095 	}
       
  1096 
       
  1097 
       
  1098 TInt DWinsMMCStack::FindAnyCardInStack(TMMCardStateEnum aState)
       
  1099 //
       
  1100 // first first active card in supplied state.  Return -1 if
       
  1101 // no active card is in supplied state.
       
  1102 //
       
  1103 	{
       
  1104 	for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
       
  1105 		{
       
  1106 		if (iCardInfo[i]->iState == aState)
       
  1107 			return i;
       
  1108 		}
       
  1109 	return -1;
       
  1110 	}
       
  1111 
       
  1112 TInt DWinsMMCStack::FindFirstCardInStack(TMMCardStateEnum aState)
       
  1113 //
       
  1114 // find card which is active on bus and in supplied state.
       
  1115 // There can be more than one active card in the the supplied state,
       
  1116 // but there should be at least one.
       
  1117 //
       
  1118 	{
       
  1119 	TInt idx = -1;
       
  1120 	for (TInt i = 0; idx != -1 && i < TotalWinsMMC_CardSlots; ++i)
       
  1121 		{
       
  1122 		if (iCardInfo[i]->iState == aState)
       
  1123 			idx = i;
       
  1124 		}
       
  1125 
       
  1126 	__ASSERT_DEBUG(idx != -1, DWinsMMCStack::Panic(DWinsMMCStack::EStkFFCNoneSel));
       
  1127 	return idx;
       
  1128 	}
       
  1129 
       
  1130 TInt DWinsMMCStack::FindOneCardInStack(TMMCardStateEnum aState)
       
  1131 //
       
  1132 // find card which is active on bus and in supplied state.
       
  1133 // There should be exactly one active card in the supplied state.
       
  1134 //
       
  1135 	{
       
  1136 	TInt idx = -1;
       
  1137 	for (TInt i = 0; i < TotalWinsMMC_CardSlots; ++i)
       
  1138 		{
       
  1139 		if (iCardInfo[i]->iState == aState)
       
  1140 			{
       
  1141 			__ASSERT_DEBUG(idx == -1, DWinsMMCStack::Panic(DWinsMMCStack::EStkFOCMultiSel));
       
  1142 			idx = i;
       
  1143 			}
       
  1144 		}
       
  1145 
       
  1146 	__ASSERT_DEBUG(idx != -1, DWinsMMCStack::Panic(DWinsMMCStack::EStkFOCNoneSel));
       
  1147 	return idx;
       
  1148 	}
       
  1149 
       
  1150 void DWinsMMCStack::SetupDiskParms(TUint aDiskSize)
       
  1151 	{	
       
  1152 //
       
  1153 //	setup parms for emulated mmc disk size
       
  1154 //
       
  1155 	// force a minimum of 32 KB total size
       
  1156 	if (aDiskSize<32)
       
  1157 		aDiskSize=32;
       
  1158 	// first setup the CSD parameters
       
  1159 	CSIZE_MULT = 0;
       
  1160 	TUint newCSIZE = aDiskSize>>1;	// with zero multiplier 1 + size parameter = size in KB / 2
       
  1161 	while((newCSIZE>0xfff)&&(CSIZE_MULT<7))	
       
  1162 		// size parameter 12 bits, multiplier 3 bits
       
  1163 		{
       
  1164 		// size parameter too big and multiplier still has room to
       
  1165 		// grow so increase multiplier and reduce size parameter
       
  1166 		CSIZE_MULT++; 
       
  1167 		newCSIZE = aDiskSize>>(1+CSIZE_MULT);
       
  1168 		}
       
  1169 	CSIZE = newCSIZE;
       
  1170 	// as CSIZE = 1 + CSIZE
       
  1171 	CSIZE--;
       
  1172 	// restrict to 12 bits
       
  1173 	if (CSIZE>0xfff)
       
  1174 		CSIZE=0xfff;
       
  1175 	// now setup TotalDiskSize
       
  1176 	TotalMDiskSize = 512 * (1+CSIZE) * (1<<(2+CSIZE_MULT));
       
  1177 	}
       
  1178 
       
  1179 // ======== TWinsMMCMediaChange ========
       
  1180 
       
  1181 #pragma warning( disable : 4355 )	// this used in initializer list
       
  1182 DWinsMMCMediaChange::DWinsMMCMediaChange(TInt aMediaChangeNum)
       
  1183 //
       
  1184 // Constructor
       
  1185 //
       
  1186 	: DMMCMediaChange(aMediaChangeNum),
       
  1187 	  iMediaChangeEnable(ETrue)
       
  1188 	{
       
  1189 
       
  1190 	iMediaDoorCloseReload=2; 	// Units: In theory-20ms, Actual-100ms
       
  1191 	}
       
  1192 #pragma warning( default : 4355 )
       
  1193 
       
  1194 TInt DWinsMMCMediaChange::Create()
       
  1195 //
       
  1196 // Initialiser.
       
  1197 //
       
  1198 	{	
       
  1199 	return(DMediaChangeBase::Create());
       
  1200 	}
       
  1201 
       
  1202 void DWinsMMCMediaChange::DoorOpenService()
       
  1203 //
       
  1204 // Handle the media change (this function, never postponed is called on media
       
  1205 // change interrupt). 
       
  1206 //
       
  1207 	{
       
  1208 	Disable();		// Disable interrupt until door closes again.
       
  1209 	iDoorOpenDfc.Enque();
       
  1210 	}
       
  1211 
       
  1212 void DWinsMMCMediaChange::DoDoorOpen()
       
  1213 //
       
  1214 // Handle media door open (called on media door open interrupt). 
       
  1215 //
       
  1216 	{
       
  1217 	iDoorClosedCount=iMediaDoorCloseReload;
       
  1218 	// Just start a ticklink to poll for door closing
       
  1219 	iTickLink.Periodic(KMediaChangeTickInterval,DWinsMMCMediaChange::Tick,this);
       
  1220     }
       
  1221 
       
  1222 void DWinsMMCMediaChange::DoDoorClosed()
       
  1223 //
       
  1224 // Handle media door closing
       
  1225 //
       
  1226 	{
       
  1227 	iTickLink.Cancel();	// Doesn't matter if wasn't enabled
       
  1228 	Enable();	// Re-enable door interrupts
       
  1229 
       
  1230 	// While the door was open the user may have changed the card in slot 0
       
  1231 	if (iStackP && *Wins::CurrentPBusDevicePtr() >= 0)
       
  1232 		iStackP->iCardInfo[0]=iStackP->iCardPool[*Wins::CurrentPBusDevicePtr()];
       
  1233 	}
       
  1234 
       
  1235 void DWinsMMCMediaChange::ForceMediaChange()
       
  1236 //
       
  1237 // Force media change
       
  1238 //
       
  1239 	{
       
  1240 	DoorOpenService();
       
  1241 	}
       
  1242 
       
  1243 TMediaState DWinsMMCMediaChange::MediaState()
       
  1244 //
       
  1245 // Return status of media changed signal.
       
  1246 //
       
  1247 	{
       
  1248 	if (iDoorClosedCount>0)
       
  1249 		return(EDoorOpen);
       
  1250 	return( (*Wins::MediaDoorOpenPtr())?EDoorOpen:EDoorClosed);
       
  1251 	}
       
  1252 
       
  1253 void DWinsMMCMediaChange::Tick(TAny *aPtr)
       
  1254 //
       
  1255 // Called on the tick to poll for door closing (called on DFC).
       
  1256 //
       
  1257 	{
       
  1258 
       
  1259 	((DWinsMMCMediaChange*)aPtr)->TickService();
       
  1260 	}
       
  1261 
       
  1262 void DWinsMMCMediaChange::TickService()
       
  1263 //
       
  1264 // Called on the tick to poll for door closing (called on DFC).
       
  1265 //
       
  1266 	{
       
  1267 
       
  1268 	__ASSERT_DEBUG(iDoorClosedCount>=0,DWinsMMCStack::Panic(DWinsMMCStack::EWinsMMCMediaChangeTickFault));
       
  1269 
       
  1270 	if (!(*Wins::MediaDoorOpenPtr()))
       
  1271 		{
       
  1272 		if (iDoorClosedCount > 0)
       
  1273 			{
       
  1274 			if (--iDoorClosedCount == 0)
       
  1275 				{
       
  1276 				iTickLink.Cancel();		// cancel door closed timer
       
  1277 				DoorClosedService();
       
  1278 				}
       
  1279 			}
       
  1280 		}
       
  1281 	else
       
  1282 		iDoorClosedCount=iMediaDoorCloseReload; // Door open so start again.
       
  1283 	}
       
  1284 
       
  1285 void DWinsMMCMediaChange::Enable()
       
  1286 //
       
  1287 // Enable media change 
       
  1288 //
       
  1289 	{
       
  1290 
       
  1291 	iMediaChangeEnable=ETrue;
       
  1292 	}
       
  1293 
       
  1294 void DWinsMMCMediaChange::Disable()
       
  1295 //
       
  1296 // Disable media change
       
  1297 //
       
  1298 	{
       
  1299 
       
  1300 	iMediaChangeEnable=EFalse;
       
  1301 	}
       
  1302 
       
  1303 void DWinsMMCMediaChange::MediaChangeCallBack(TAny *aPtr)
       
  1304 //
       
  1305 // Static called on media change
       
  1306 //
       
  1307 	{
       
  1308 	DWinsMMCMediaChange* mc=(DWinsMMCMediaChange*)aPtr;
       
  1309 	if (mc!=NULL&&mc->iMediaChangeEnable)
       
  1310 		mc->DoorOpenService();
       
  1311 	}
       
  1312 
       
  1313 // ======== TWinsCardInfo ========
       
  1314 
       
  1315 void TWinsCardInfo::GetCSD(TUint8* aResp) const
       
  1316 	{
       
  1317 	// Bits 127-96
       
  1318 	TUint32 csd=(KCsdStructure<<30); 	/* CSD_STRUCTURE */
       
  1319 	csd|=		(KCsdSpecVers<<26); 	/* SPEC_VERS */
       
  1320 	csd|=		(0x0E<<16);				/* TAAC: 1mS */  
       
  1321 	csd|=		(0x0A<<8);				/* NSAC: 1000 */  
       
  1322 	csd|=		(0x59);					/* TRAN_SPEED: 5.0Mbit/s */  
       
  1323 	TMMC::BigEndian4Bytes(&aResp[0],csd);
       
  1324 
       
  1325 	// Bits 95-64
       
  1326 	TUint32 lockBit = KMMCCmdClassLockCard;
       
  1327 #ifdef __CARD0_NOT_LOCKABLE__
       
  1328 	if (*Wins::CurrentPBusDevicePtr() == 0)
       
  1329 		lockBit = 0;
       
  1330 #endif
       
  1331 #ifdef __CARD1_NOT_LOCKABLE__
       
  1332 	if (*Wins::CurrentPBusDevicePtr() == 1)
       
  1333 		lockBit = 0;
       
  1334 #endif
       
  1335 	const TUint32 ccc = 
       
  1336 			KMMCCmdClassBasic | KMMCCmdClassBlockRead
       
  1337 		|	KMMCCmdClassBlockWrite | lockBit;
       
  1338 	csd=		(ccc<<20); 	/* CCC: classes 0, 2, 4, and 7 */
       
  1339 	csd|=		(0x9<<16); 	/* READ_BL_LEN: 512 bytes */
       
  1340 	csd|=		(0x0<<15);	/* READ_BL_PARTIAL: No */  
       
  1341 	csd|=		(0x0<<14);	/* WRITE_BLK_MISALIGN: No */  
       
  1342 	csd|=		(0x0<<13);	/* READ_BLK_MISALIGN: No */  
       
  1343 	csd|=		(0x0<<12);	/* DSR_IMP: No DSR */ 
       
  1344 	csd|=		((DWinsMMCStack::CSIZE>>10&3)<<8);			/* C_SIZE: MMCSz Kb */
       
  1345 	csd|=		((DWinsMMCStack::CSIZE>>2) & 0xFF);			/* C_SIZE: MMCSz Kb */
       
  1346 	TMMC::BigEndian4Bytes(&aResp[4],csd); 
       
  1347 	// Bits 63-32
       
  1348 	csd=		((DWinsMMCStack::CSIZE&3)<<30); 			/* C_SIZE: MMCSz Kb */
       
  1349 	csd|=		(0x1<<27); 	/* VDD_R_CURR_MIN: 1mA */
       
  1350 	csd|=		(0x1<<24);	/* VDD_R_CURR_MAX: 5mA */  
       
  1351 	csd|=		(0x2<<21); 	/* VDD_W_CURR_MIN: 5mA */
       
  1352 	csd|=		(0x3<<18);	/* VDD_W_CURR_MAX: 25mA */  
       
  1353 	csd|=		((DWinsMMCStack::CSIZE_MULT&0x07)<<15);		/* C_SIZE_MULT: 0 */  
       
  1354 	csd|=		(0x0<<10);	/* SECTOR_SIZE: 1 write block */  
       
  1355 	csd|=		(0x0<<5);	/* ERASE_GRP_SIZE: 1 secotr */  
       
  1356 	csd|=		(0x0);		/* WP_GRP_SIZE: 1 erase group */  
       
  1357 	TMMC::BigEndian4Bytes(&aResp[8],csd); 
       
  1358 	// Bits 31-0
       
  1359 	csd=		(0x0<<31); 	/* WP_GRP_ENABLE: No */
       
  1360 	csd|=		(0x0<<29); 	/* DEFAULT_ECC: ? */
       
  1361 	csd|=		(0x3<<26);	/* R2W_FACTOR: 8 */  
       
  1362 	csd|=		(0x9<<22); 	/* WRITE_BL_LEN: 512 bytes */
       
  1363 	csd|=		(0x0<<21);	/* WRITE_BL_PARTIAL: No */  
       
  1364 	csd|=		(0x0<<15);	/* FILE_FORMAT_GRP: Hard disk */  
       
  1365 	csd|=		(0x0<<14);	/* COPY: original */  
       
  1366 	csd|=		(0x0<<13);	/* PERM_WRITE_PROTECT: No */  
       
  1367 	csd|=		(0x0<<12);	/* TMP_WRITE_PROTECT: No */  
       
  1368 	csd|=		(0x0<<10);	/* FILE_FORMAT: Hard disk */  
       
  1369 	csd|=		(0x0<<8);	/* ECC: None */  
       
  1370 	csd|=		(0x0<<1);	/* CRC: ? */  
       
  1371 	csd|=		(0x1);		/* not used */  
       
  1372 	TMMC::BigEndian4Bytes(&aResp[12],csd);
       
  1373 	}
       
  1374 
       
  1375 // ======== TWinsMMCPsu ========
       
  1376 
       
  1377 
       
  1378 DWinsMMCPsu::DWinsMMCPsu(TInt aVccNum, TInt aMcId)
       
  1379 //
       
  1380 // Constructor.
       
  1381 //
       
  1382 	: DMMCPsu(aVccNum, aMcId)
       
  1383 	{}
       
  1384 
       
  1385 TInt DWinsMMCPsu::DoCreate()
       
  1386 //
       
  1387 // Initialise the PSU
       
  1388 //
       
  1389     {
       
  1390 	// Nothing to do
       
  1391 	return KErrNone;
       
  1392     }
       
  1393 
       
  1394 void DWinsMMCPsu::DoSetState(TPBusPsuState aState)
       
  1395 //
       
  1396 // Turn on/off the PSU. If it is possible to adjust the output voltage on this
       
  1397 // PSU then retreive the required voltage level from TMMCPsu::iVoltageSetting
       
  1398 // (which is in OCR register format).
       
  1399 //
       
  1400     {
       
  1401 
       
  1402     switch (aState)
       
  1403         {
       
  1404         case EPsuOff:
       
  1405             break;
       
  1406         case EPsuOnFull:
       
  1407             break;
       
  1408         case EPsuOnCurLimit:
       
  1409             break;
       
  1410         }
       
  1411     }
       
  1412 
       
  1413 TInt DWinsMMCPsu::VoltageInMilliVolts()
       
  1414 //
       
  1415 // Return the level of the PSU (in mV) or -ve if error.
       
  1416 //
       
  1417     {
       
  1418 
       
  1419     return(0);
       
  1420     }
       
  1421 
       
  1422 void DWinsMMCPsu::DoCheckVoltage()
       
  1423 //
       
  1424 // Check the voltage level of the PSU is as expected. Returns either KErrNone, KErrGeneral 
       
  1425 // to indicate the pass/fail state or KErrNotReady if the voltage check isn't complete.
       
  1426 //
       
  1427     {
       
  1428 	ReceiveVoltageCheckResult(KErrNone);
       
  1429     }
       
  1430 
       
  1431 void DWinsMMCPsu::PsuInfo(TPBusPsuInfo &anInfo)
       
  1432 //
       
  1433 // Return machine info relating to the MMC PSU supply
       
  1434 //
       
  1435     {
       
  1436 
       
  1437 	anInfo.iVoltageSupported=0x00040000; // 3.0V (OCR reg. format).
       
  1438 	anInfo.iMaxCurrentInMicroAmps=0;
       
  1439 	anInfo.iVoltCheckInterval=0;
       
  1440 	anInfo.iVoltCheckMethod=EPsuChkComparator;
       
  1441 	anInfo.iNotLockedTimeOut=0;
       
  1442 	anInfo.iInactivityTimeOut=5;
       
  1443     }
       
  1444