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