os/boardsupport/emulator/emulatorbsp/specific/sdcard/sdcard4c/pp_cprm.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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_cprm.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 // ======== DWinsCPRMStack ========
    91 
    92 DWinsCPRMStack::DWinsCPRMStack(TInt aBus, DMMCSocket* aSocket)
    93 : DCPRMStack(aBus, aSocket)
    94 	{	
    95 	iAddressedCard=KBroadcastToAllCards;
    96 //	iCMD42Failed=EFalse;
    97 	}
    98 
    99 
   100 TInt DWinsCPRMStack::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=DCPRMStack::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 DWinsCPRMStack::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 					DWinsCPRMStack::Panic(DWinsCPRMStack::EWinsMMCBadMachineInfo));
   200 	}
   201 
   202 void DWinsCPRMStack::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 DWinsCPRMStack::GetBufferInfo(TUint8** aMDBuf, TInt* aMDBufLen)
   224 	{
   225 	*aMDBuf = iMDBuf;
   226 	*aMDBufLen = iMDBufLen;
   227 	}
   228 
   229 void DWinsCPRMStack::Panic(TWinsMMCPanic aPanic)
   230 	{
   231 	_LIT(KPncNm,"PBUS-MMCSD-WINS");
   232 	Kern::PanicCurrentThread(KPncNm,aPanic);
   233 	}
   234 
   235 TInt DWinsCPRMStack::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 DWinsCPRMStack::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 DWinsCPRMStack::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 DWinsCPRMStack::InitClockOff()
   339 	{
   340 	// empty.
   341 	}
   342 
   343 void DWinsCPRMStack::ASSPReset()
   344 	{
   345 	// empty.
   346 	}
   347 
   348 void DWinsCPRMStack::ASSPDisengage()
   349 	{
   350 	// empty.
   351 	}
   352 
   353 void DWinsCPRMStack::DoPowerDown()
   354 	{
   355 	// empty.
   356 	}
   357 
   358 LOCAL_C TInt SetMediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,const TDesC8& aPasswd)
   359 // 
   360 // Set the password for local drive 'aLocalDrive', card number 'aCardNum' to 'aPasswd' - as an
   361 // environment variable. Note that the card number is only relevant where the emulated drive
   362 // supports card hot-swapping (i.e. F4 whilst F5 is held down).
   363 //
   364 	{
   365 	// Setup the appropriate environment variable string '_EPOC_LocDrv_<locDrvNum>_PWORD_<cardNum>'
   366 	TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
   367 
   368 	envVar[13]=(TUint16)('0'+aSocketNum);
   369 	envVar[21]=(TUint16)('0'+aCardNum);
   370 	
   371 	// Setup the new value of the environment variable
   372 	TUint16	envVal[100];
   373 	TInt len=aPasswd.Length();
   374 
   375 	// the password may be empty if a card's password is cleared
   376 	if (len>(100-1))
   377 		return(KErrArgument);
   378 	memcpy(&envVal[0],reinterpret_cast<const TUint16 *>(aPasswd.Ptr()),len);
   379 	envVal[len>>1]='\0';
   380 
   381 	// Now set the new value for the environment variable
   382 	if (SetEnvironmentVariable(envVar,&envVal[0]))
   383 		return(KErrNone);
   384 
   385 	return KErrGeneral;
   386 	}
   387 
   388 LOCAL_C TInt MediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,TDes8& aPasswd)
   389 // 
   390 // Get the password for local drive 'aLocalDrive', card number 'aCardNum' into 'aPasswd' - from
   391 // an environment variable. Note that the card number is only relevant where the emulated drive
   392 // supports card hot-swapping (i.e. F4 whilst F5 is held down).
   393 //
   394 	{
   395 	TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
   396 
   397 	envVar[13]=(TUint16)('0'+aSocketNum);
   398 	envVar[21]=(TUint16)('0'+aCardNum);
   399 	
   400 	TUint16 envVal[100];	// To hold the value of the retreived environment variable
   401 	
   402 	DWORD len=GetEnvironmentVariable(envVar,&envVal[0],100);
   403 	if (len>(TUint)100)
   404 		return(KErrGeneral);
   405 	if (len)
   406 		{
   407 		// Found the requested environment variable so there is a password for this local drive / card. 
   408 		if ((len<<1)<=KMaxMediaPassword)
   409 			{
   410 			aPasswd.FillZ(KMaxMediaPassword);
   411 			aPasswd.Zero();
   412 			aPasswd.Copy(reinterpret_cast<TUint8*>(&envVal[0]),len<<1);
   413 			return(KErrNone);	
   414 			}
   415 		else	
   416 			return(KErrGeneral);	
   417 		}
   418 
   419 	return(KErrNotFound);
   420 	}
   421 
   422 TMMCErr DWinsCPRMStack::DoPowerUpSM()
   423 	{
   424 	enum states
   425 		{
   426 		EStBegin=0,
   427 		EStEnd
   428 		};
   429 
   430 	SMF_BEGIN
   431 
   432 		if(MMCSocket()->iVcc->SetState(EPsuOnCurLimit) != KErrNone)
   433 			return KMMCErrHardware;
   434 
   435 		for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   436 			{
   437 			// if card has a password, it will be locked on power up
   438 			TInt cardNum = (i==0) ? *Wins::CurrentPBusDevicePtr() : i + 1;
   439 			if (	cardNum >= 0
   440 				&&	MediaPasswordEnvironmentVar(
   441 						MMCSocket()->iSocketNumber, cardNum, *(iCardInfo[i]->iPWD))
   442 					==	KErrNone)
   443 				{
   444 				iCardInfo[i]->iIsLocked = (iCardInfo[i]->iPWD->Length() > 0);
   445 				}
   446 			else	
   447 				iCardInfo[i]->iIsLocked=EFalse;
   448 
   449 			iCardInfo[i]->iState = ECardStateIdle;
   450 			iCardInfo[i]->iRCA=0x0001;		// Default RCA - spec 2.2, s4.2.1, 5.4
   451 			}
   452 
   453 		ReportPowerUp();
   454 
   455 	SMF_END
   456 	}
   457 
   458 TMMCErr DWinsCPRMStack::InitClockOnSM()
   459 	{
   460 	enum states
   461 		{
   462 		EStBegin=0,
   463 		EStEnd
   464 		};
   465 	SMF_BEGIN
   466 
   467 	SMF_END
   468 	}
   469 
   470 void DWinsCPRMStack::AddressCard(TInt aCardNumber)
   471 	{
   472 	iAddressedCard = aCardNumber;
   473 	}
   474 
   475 
   476 TInt DWinsCPRMStack::GetTargetSlotNumber(const TRCA& anRCA)
   477 //
   478 // when the controller is given a command with an embedded RCA, this function
   479 // works out which physical card slot it corresponds to.  If no card has been
   480 // assigned the RCA then it returns -1.
   481 //
   482 	{
   483 	TInt targetIdx = -1;
   484 
   485 	for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   486 		{
   487 		if (iCardInfo[i]->iRCA==anRCA)
   488 			{
   489 			targetIdx=i;
   490 			break;
   491 			}
   492 		}
   493 
   494 	return(targetIdx);
   495 	}
   496 
   497 TMMCErr DWinsCPRMStack::IssueMMCCommandSM()
   498 	{
   499 	enum states
   500 		{
   501 		EStBegin=0,
   502 		EStEnd
   503 		};
   504 
   505 	TMMCCommandDesc& cmd = Command();
   506 
   507 	// If the command contains an embedded RCA then extract it	
   508 	TRCA tgtRCA=0;
   509 	TBool supRCA=EFalse;
   510 	if (/*cmd.iCommand == ECmdSetRelativeAddr	||	*/cmd.iCommand == ECmdSelectCard
   511 	||	cmd.iCommand == ECmdSendCSD			||	cmd.iCommand == ECmdSendCID
   512 	||	cmd.iCommand == ECmdSendStatus		||	cmd.iCommand == ECmdGoInactiveState
   513 	||	cmd.iCommand == ECmdFastIO 			||  cmd.iCommand == ECmdAppCmd )
   514 		{
   515 		if ((cmd.iArgument >> 16) != 0)
   516 			{
   517 			supRCA=ETrue;
   518 			tgtRCA=TUint16(cmd.iArgument >> 16);
   519 			}
   520 		}
   521 
   522 	// if the card contains an embedded RCA, work out which slot it corresponds to.
   523 	// At the end of the function, this card is used to generate the R1 response.
   524 	// Assume that if rca is supplied it either corresponds to the selected card or
   525 	// broadcast mode is on.  (An exception is CMD7 with arg0 to deselect all cards.)
   526 
   527 	TInt targetCard = supRCA ? GetTargetSlotNumber(tgtRCA) : iAddressedCard;
   528 	TBool rto = EFalse;							// response timeout
   529 
   530 	// if try to access card zero has been set to holding no card via F5 / F4 then timeout.
   531 	if ((targetCard == 0) && *Wins::CurrentPBusDevicePtr() < 0)
   532 		return KMMCErrResponseTimeOut;
   533 	
   534 	HANDLE winHandle;
   535 
   536 	// CMD42 is a data transfer command.  That means the R1 response that it returns
   537 	// immediately is the state it is in on receiving the data block, and not after
   538 	// processing it.  If the data block is invalid then LOCK_UNLOCK_FAILED will be
   539 	// set in the R1 response which is sent in reply to the next command.
   540 
   541 	TBool nextCMD42Failed = EFalse;
   542 	TBool lock_unlock_failed=EFalse;
   543 
   544 	// When the card is locked, it will only respond to basic command class (0) and
   545 	// lock card command class (7).  An exception is CMD16.  This is sent before CMD42,
   546 	// but is classified (MMC Spec 23.2, table 5) as belonging to classes 2 and 4.
   547 	// For data transfer commands, LOCK_UNLOCK_FAIL is set in response to the following
   548 
   549 	TMMCCommandEnum origCmd = cmd.iCommand;
   550 
   551 	// if targetting locked card...
   552 	if (targetCard != KBroadcastToAllCards && iCardInfo[targetCard]->iIsLocked)
   553 		{
   554 		// ...and not command used in init or CMD42 sequence...
   555 		if (!(	((cmd.iSpec.iCommandClass & (KMMCCmdClassApplication | KMMCCmdClassBasic | KMMCCmdClassLockCard)) != 0)
   556 			||	(cmd.iCommand == ECmdSetBlockLen) || (cmd.iCommand == ECmdAppCmd) ))
   557 			{
   558 			lock_unlock_failed = ETrue;
   559 			cmd.iCommand = (TMMCCommandEnum) -1;	// skip case processing
   560 			}
   561 		}
   562 
   563 	SMF_BEGIN
   564 
   565 	switch (cmd.iCommand)
   566 		{
   567 		case ECmdGoIdleState:	// CMD0
   568 			if (iAddressedCard != KBroadcastToAllCards)
   569 				iCardInfo[iAddressedCard]->iState = ECardStateIdle;
   570 			else
   571 				{
   572 				for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   573 					iCardInfo[i]->iState = ECardStateIdle;
   574 				}
   575 			break;
   576 
   577 		case ECmd41:
   578 		case ECmdSendOpCond:	// CMD1
   579 			{
   580 			if (iAddressedCard != KBroadcastToAllCards)
   581 				iCardInfo[iAddressedCard]->iState = ECardStateReady;
   582 			else
   583 				{
   584 				for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   585 					iCardInfo[i]->iState = ECardStateReady;
   586 				}
   587 
   588 			// bit31 is set to indicate cards are not still powering up
   589 			TUint32 r3 = KMMCWinsCardOCRValue | KMMCOCRBusy;
   590 			TMMC::BigEndian4Bytes(cmd.iResponse, r3);
   591 			}
   592 			break;
   593 
   594 		case ECmdAllSendCID:	// CMD2
   595 			{
   596 			TInt idx;
   597 			if (iAddressedCard != KBroadcastToAllCards)
   598 				{
   599 				idx = iAddressedCard;
   600 				__ASSERT_DEBUG(
   601 					iCardInfo[iAddressedCard]->iState == ECardStateReady,
   602 					DWinsCPRMStack::Panic(DWinsCPRMStack::EStkIMCBadStateCmd2));
   603 				}
   604 			else
   605 				idx = FindAnyCardInStack(ECardStateReady);
   606 
   607 			if (idx == -1)
   608 				rto = ETrue;
   609 			else
   610 				{
   611 				iCardInfo[idx]->iCID.Copy(cmd.iResponse);
   612 				iCardInfo[idx]->iState = ECardStateIdent;
   613 				}
   614 			}
   615 			break;
   616 
   617 		case ECmdSetRelativeAddr:	// CMD3
   618 			{
   619 			TInt idx;
   620 			if (iAddressedCard != KBroadcastToAllCards)
   621 				{
   622 				__ASSERT_DEBUG(
   623 					iCardInfo[iAddressedCard]->iState == ECardStateIdent,
   624 					DWinsCPRMStack::Panic(DWinsCPRMStack::EStkIMCBadStateCmd3));
   625 				
   626 				if (iCardInfo[iAddressedCard]->iIsSDCard)
   627 					{
   628 					static TUint16 RCACounter = 0x1234;
   629 					// SD Cards publish RCAs
   630 					++RCACounter;
   631 					iCardInfo[iAddressedCard]->iRCA = RCACounter;
   632 					iCardInfo[iAddressedCard]->iState = ECardStateStby;
   633 					TUint32 r6 = TUint32(RCACounter) << 16;
   634 					TMMC::BigEndian4Bytes(&cmd.iResponse[0],r6); // Ignore bits 47-40
   635 					}
   636 				else
   637 					{
   638 					iCardInfo[iAddressedCard]->iRCA = TUint16(cmd.iArgument >> 16);
   639 					iCardInfo[iAddressedCard]->iState=ECardStateStby;
   640 					}
   641 				}
   642 			else
   643 				{
   644 				// MultiMediaCards are assigned RCAs
   645 				idx = FindOneCardInStack(ECardStateIdent);
   646 				iCardInfo[iAddressedCard]->iRCA = TUint16(cmd.iArgument >> 16);
   647 				iCardInfo[iAddressedCard]->iState=ECardStateStby;
   648 				targetCard = iAddressedCard;
   649 				}
   650 			}
   651 			break;
   652 
   653 		case ECmd6:
   654 			// if ACMD6 then change bus width
   655 			if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
   656 				{
   657 				switch (cmd.iArgument)
   658 					{
   659 				case 0x00:
   660 					iCardInfo[iAddressedCard]->iBusWidth = 1;
   661 					break;
   662 				case 0x02:
   663 					iCardInfo[iAddressedCard]->iBusWidth = 4;
   664 					break;
   665 				default:
   666 					DWinsCPRMStack::Panic(DWinsCPRMStack::EStkIMCCmd6InvalidWidth);
   667 					break;
   668 					}
   669 				}
   670 			break;
   671 
   672 		case ECmdSelectCard:		// CMD7
   673 			{
   674 			// switch to broadcast mode so the currently selected and new cards
   675 			// receive the command simultaneously.
   676 
   677 			TInt idx = FindAnyCardInStack(ECardStateTran);
   678 			if (idx != -1)
   679 				iCardInfo[idx]->iState = ECardStateStby;
   680 			if ((iAddressedCard=targetCard) == KBroadcastToAllCards)
   681 				rto = ETrue;
   682 			else
   683 				{
   684 				iCardInfo[targetCard]->iState = ECardStateTran;
   685 				targetCard = targetCard;
   686 				}
   687 			}
   688 			break;
   689 
   690 		case ECmdSendStatus:
   691 			// R1 response so status return as for any other R1 command.
   692 			if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
   693 				{
   694 				__ASSERT_DEBUG(
   695 					iCardInfo[targetCard]->iIsSDCard,
   696 					DWinsCPRMStack::Panic(DWinsCPRMStack::EStkICMACMD13NotSD));
   697 
   698 				memset(cmd.iDataMemoryP, 0, KSDStatusBlockLength);
   699 				if (iCardInfo[targetCard]->iBusWidth == 1)
   700 					cmd.iDataMemoryP[0] = 0x00 << 6;
   701 				else	// if (iCardInfo[targetCard]->iBusWidth == 4)
   702 					cmd.iDataMemoryP[0] = 0x02 << 6;
   703 				cmd.iDataMemoryP[7] = 0x28;		// PROTECTED_AREA_SIZE
   704 				}
   705 			break;
   706 
   707 		case ECmdReadSingleBlock:
   708 		case ECmdReadMultipleBlock:
   709 			{
   710 			winHandle=iCardInfo[targetCard]->iAreaHandles[KSDUserArea];
   711 
   712 			if ( cmd.iSpec.iUseStopTransmission && cmd.iBlockLength >= cmd.iTotalLength)
   713 				return( KMMCErrNotSupported );
   714 
   715     		TMMCErr err;
   716 			TInt pos = cmd.iArgument;
   717     		if (SetFilePointer(winHandle,pos,NULL,FILE_BEGIN)==0xffffffffu)
   718         		err=MapLastErrorMmc();
   719     		else
   720         		{
   721 	    		DWORD res;
   722 				TInt len = cmd.iTotalLength;
   723 		        if (ReadFile(winHandle,(TAny*)cmd.iDataMemoryP,len,&res,NULL)==FALSE)
   724                     err=MapLastErrorMmc();
   725                 else if (res!=(DWORD)len)
   726                     err=KMMCErrGeneral;
   727                 else
   728                     err=KMMCErrNone;
   729 				}
   730 			if (err!=KMMCErrNone)
   731 				return(err);
   732 			break;
   733 			}
   734 
   735 		case ECmd22:
   736 			if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
   737 				{
   738 				TMMC::BigEndian4Bytes(cmd.iResponse, iMBWOKBlocks);
   739 				}
   740 			break;
   741 		// ------------------------------------------------------------------
   742 		case ECmdWriteBlock:
   743 		case ECmdWriteMultipleBlock:
   744 			{
   745 			TUint32 writeLen;
   746 
   747 			// periodically fail multi-block writes to test ACMD22 error recovery
   748 			if (cmd.iCommand != ECmdWriteMultipleBlock)
   749 				writeLen = cmd.iTotalLength;
   750 			else
   751 				{
   752 				const TInt KMaxFailCnt = 4;
   753 				static TInt failCnt = 0;
   754 				const TInt KMaxFailBlock = 4;
   755 				static TInt failBlocks = 0;
   756 				
   757 				failCnt = (failCnt + 1) % KMaxFailCnt;
   758 				if (failCnt != 0)
   759 					writeLen = cmd.iTotalLength;
   760 				else
   761 					{
   762 					failBlocks = (failBlocks + 1) % KMaxFailBlock;
   763 					
   764 					// fail at least one block
   765 					TInt totalBlocks = cmd.iTotalLength / cmd.iBlockLength;
   766 					TInt blocksToFail = Min(failBlocks + 1, totalBlocks);	// fail at least one block
   767 					iMBWOKBlocks = (totalBlocks - blocksToFail);
   768 					writeLen = iMBWOKBlocks * cmd.iBlockLength;
   769 					if (writeLen == 0)
   770 						return KMMCErrDataTimeOut;
   771 					}
   772 				}
   773 			
   774 			HANDLE h=iCardInfo[targetCard]->iAreaHandles[KSDUserArea];
   775 
   776     		TMMCErr err;
   777 			TInt pos = cmd.iArgument;
   778     		if (SetFilePointer(h, pos, NULL, FILE_BEGIN)==0xffffffffu)
   779         		err = MapLastErrorMmc();
   780     		else
   781         		{
   782 	    		DWORD res;
   783 				if (! WriteFile(h, (LPCVOID)cmd.iDataMemoryP,writeLen,&res,NULL))
   784                     err=MapLastErrorMmc();
   785                 else if (res!=(DWORD)writeLen)
   786                     err=KMMCErrGeneral;
   787                 else
   788                     err=KMMCErrNone;
   789 				}
   790 
   791 			if (err!=KMMCErrNone)
   792 				return(err);
   793 			if (writeLen != cmd.iTotalLength)
   794 				return KMMCErrDataTimeOut;
   795 			}
   796 			break;
   797 
   798 		case ECmdAppCmd:
   799 			// targetCard == -1 when ACMD41 being sent because not yet supplied
   800 			if (iAddressedCard != KBroadcastToAllCards)
   801 				{
   802 				// timeout if addressed card is not SD
   803 				if (! iCardInfo[iAddressedCard]->iIsSDCard)
   804 					rto = ETrue;
   805 				}
   806 			else
   807 				{
   808 				// request sent to specific non-SD card
   809 				if (targetCard != -1 && ! iCardInfo[targetCard]->iIsSDCard)
   810 					rto = ETrue;
   811 				}
   812 			break;
   813 
   814 		case ECmdSendCSD:
   815 			{
   816 			iCardInfo[targetCard]->GetCSD(cmd.iResponse);
   817 			break;
   818 			}
   819 
   820 		// ------------------------------------------------------------------
   821 		case ECmdLockUnlock:
   822 			// in EPOC, Lock() does not actually lock the card.  It just sets the
   823 			// password.  This means that the card is still accessible to the user,
   824 			// but must be unlocked the next time it is powered up.
   825 
   826 			// a real card will transiently go into rcv and prg state while processing
   827 			// this command.  When finished, it will fall back into tran state.
   828 			// The R1 response is sent immediately after CMD42.  CIMReadWriteBlocksSM()
   829 			// sends CMD13 to find out whether or not LOCK_UNLOCK_FAIL was set.
   830 
   831 			// the asserts in this case protect against invalid data being sent from the
   832 			// media driver.  A real card would fail these corrupt data blocks.
   833 
   834 			{
   835 			const TInt8 cmd_byte(*cmd.iDataMemoryP);
   836 			__ASSERT_DEBUG(										// ensure not CLR_PWD && SET_PWD
   837 				!((cmd_byte & KMMCLockUnlockClrPwd) && (cmd_byte & KMMCLockUnlockSetPwd)),
   838 				DWinsCPRMStack::Panic(DWinsCPRMStack::EWinsMMCCorruptCommand) );
   839 			
   840 			__ASSERT_DEBUG(										// not actually lock a card
   841 				!(cmd_byte & KMMCLockUnlockLockUnlock),
   842 				DWinsCPRMStack::Panic(DWinsCPRMStack::EWinsMMCLockAttempt) );
   843 
   844 			if (cmd_byte & KMMCLockUnlockErase)					// ERASE (not supported)
   845 				return KMMCErrNotSupported;
   846 
   847 			const TInt8 pwd_len = *(cmd.iDataMemoryP + 1);
   848 			const TPtrC8 pwd(cmd.iDataMemoryP + 2, pwd_len);
   849 
   850 			if ((cmd_byte & KMMCLockUnlockClrPwd) != 0)			// CLR_PWD == 1
   851 				{
   852 				__ASSERT_DEBUG(
   853 					pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
   854 					DWinsCPRMStack::Panic(DWinsCPRMStack::EWinsMMCCorruptCommand));
   855 
   856 				if (iCardInfo[targetCard]->iIsLocked)						// clear when locked
   857 					nextCMD42Failed = ETrue;
   858 				else														// clear when unlocked
   859 					{
   860 					if (iCardInfo[targetCard]->iPWD->Compare(pwd) != 0)		// clear when unlocked with wrong password
   861 						nextCMD42Failed = ETrue;
   862 					else													// clear when unlocked with right password
   863 						{
   864 						// Clear from password store 
   865 						iCardInfo[targetCard]->iPWD->Zero();
   866 						iCardInfo[targetCard]->iIsLocked = EFalse;
   867 						nextCMD42Failed = EFalse;
   868 						
   869 						// Clear from environment settings
   870 						TInt cardNum=(targetCard==0) ? *Wins::CurrentPBusDevicePtr() : 0; // Can't be -1 at this stage
   871 						SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[targetCard]->iPWD));
   872 						}
   873 					}
   874 				}
   875 			else if ((cmd_byte & KMMCLockUnlockSetPwd) == 0)	// SET_PWD == 0: unlock
   876 				{
   877 				__ASSERT_DEBUG(
   878 					pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
   879 					DWinsCPRMStack::Panic(DWinsCPRMStack::EWinsMMCCorruptCommand) );
   880 				
   881 				if (! iCardInfo[targetCard]->iIsLocked)						// unlock when unlocked
   882 					nextCMD42Failed = ETrue;
   883 				else
   884 					{
   885 					if (iCardInfo[targetCard]->iPWD->Compare(pwd) != 0)		// unlock when locked with wrong password
   886 						nextCMD42Failed = ETrue;
   887 					else													// unlock when locked with right password
   888 						{
   889 						iCardInfo[targetCard]->iIsLocked = EFalse;
   890 						nextCMD42Failed = EFalse;
   891 						}
   892 					}
   893 				}
   894 			else /* ((cmd_byte & KMMCLockUnlockSetPwd) != 0) */	// SET_PWD == 1
   895 				{
   896 				__ASSERT_DEBUG(
   897 					cmd_byte & KMMCLockUnlockSetPwd,
   898 					DWinsCPRMStack::Panic(DWinsCPRMStack::EWinsMMCCorruptCommand) );
   899 
   900 				// if pwd_len < iCardInfo[targetCard]->iPWD->Length() then data block must be invalid.
   901 				// This can be caused by bad user input rather than inaccurate formation.
   902 				if (!(	pwd_len >= iCardInfo[targetCard]->iPWD->Length()
   903 					&&	pwd_len <= iCardInfo[targetCard]->iPWD->Length() + KMaxMediaPassword ))
   904 					{
   905 					nextCMD42Failed = ETrue;
   906 					}
   907 				else
   908 					{
   909 					const TInt old_pwd_len = iCardInfo[targetCard]->iPWD->Length();
   910 					TPtrC8 old_pwd(cmd.iDataMemoryP + 2, old_pwd_len);
   911 					TPtrC8 new_pwd(cmd.iDataMemoryP + 2 + old_pwd_len, pwd_len - old_pwd_len);
   912 
   913 					// card must not be locked and supplied current password must be correct
   914 					if (iCardInfo[targetCard]->iIsLocked || iCardInfo[targetCard]->iPWD->Compare(old_pwd) != 0)
   915 						nextCMD42Failed = ETrue;
   916 					else
   917 						{
   918 						// Set in password store
   919 						iCardInfo[targetCard]->iPWD->Copy(new_pwd);
   920 						nextCMD42Failed = EFalse;
   921 						
   922 						// Set in environment settings
   923 						TInt cardNum=(targetCard==0) ? *Wins::CurrentPBusDevicePtr() : 0; // Can't be -1 at this stage
   924 						SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[targetCard]->iPWD));
   925 						}
   926 					}
   927 				}	// else /* ((cmd_byte & KMMCLockUnlockSetPwd) != 0) */
   928 			}	// case ECmdLockUnlock
   929 		// ------------------------------------------------------------------
   930 		default:
   931 			break;
   932 		}
   933 
   934 	if (rto)
   935 		return(KMMCErrResponseTimeOut);
   936 
   937 	cmd.iCommand = origCmd;
   938 	// If this is an R1 or R1b response type command then return card status as a response
   939 	if (	targetCard != -1
   940 		&&	(cmd.iSpec.iResponseType==ERespTypeR1 || cmd.iSpec.iResponseType==ERespTypeR1B) )
   941 		{
   942 		TUint32 resp(
   943 				iCardInfo[targetCard]->iState
   944 			|	((iCardInfo[targetCard]->iIsLocked ? 1 : 0) << 25)
   945 			|	((lock_unlock_failed ? 1 : 0) << 24) );
   946 
   947 		if (iCMD42Failed)								// previous CMD42
   948 			{
   949 			resp |= KMMCStatErrLockUnlock;
   950 			nextCMD42Failed = EFalse;
   951 			}
   952 		iCMD42Failed = nextCMD42Failed;
   953 		TMMC::BigEndian4Bytes(&cmd.iResponse[0],resp); // Ignore bits 47-40
   954 		}
   955 	SMF_END
   956 	}
   957 
   958 TInt DWinsCPRMStack::FindAnyCardInStack(TMMCardStateEnum aState)
   959 //
   960 // first first active card in supplied state.  Return -1 if
   961 // no active card is in supplied state.
   962 //
   963 	{
   964 	if (iAddressedCard != KBroadcastToAllCards)
   965 		return (iCardInfo[iAddressedCard]->iState == aState) ? iAddressedCard : -1;
   966 	else
   967 		{
   968 		for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   969 			{
   970 			if (iCardInfo[i]->iState == aState)
   971 				return i;
   972 			}
   973 
   974 		return -1;
   975 		}
   976 	}
   977 
   978 TInt DWinsCPRMStack::FindFirstCardInStack(TMMCardStateEnum aState)
   979 //
   980 // find card which is active on bus and in supplied state.
   981 // There can be more than one active card in the the supplied state,
   982 // but there should be at least one.
   983 //
   984 	{
   985 	if (iAddressedCard != KBroadcastToAllCards)
   986 		{
   987 		__ASSERT_DEBUG(iCardInfo[iAddressedCard]->iState == aState, DWinsCPRMStack::Panic(DWinsCPRMStack::EStkFFCNotSelCard));
   988 		return iAddressedCard;
   989 		}
   990 	else
   991 		{
   992 		TInt idx = -1;
   993 		for (TInt i = 0; idx != -1 && i < KTotalWinsCardSlots; ++i)
   994 			{
   995 			if (iCardInfo[i]->iState == aState)
   996 				idx = i;
   997 			}
   998 
   999 		__ASSERT_DEBUG(idx != -1, DWinsCPRMStack::Panic(DWinsCPRMStack::EStkFFCNoneSel));
  1000 		return idx;
  1001 		}
  1002 	}
  1003 
  1004 TInt DWinsCPRMStack::FindOneCardInStack(TMMCardStateEnum aState)
  1005 //
  1006 // find card which is active on bus and in supplied state.
  1007 // There should be exactly one active card in the supplied state.
  1008 //
  1009 	{
  1010 	if (iAddressedCard != KBroadcastToAllCards)
  1011 		{
  1012 		__ASSERT_DEBUG(iCardInfo[iAddressedCard]->iState == aState, DWinsCPRMStack::Panic(DWinsCPRMStack::EStkFOCNotSelCard));
  1013 		return iAddressedCard;
  1014 		}
  1015 	else
  1016 		{
  1017 		TInt idx = -1;
  1018 		for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
  1019 			{
  1020 			if (iCardInfo[i]->iState == aState)
  1021 				{
  1022 				__ASSERT_DEBUG(idx == -1, DWinsCPRMStack::Panic(DWinsCPRMStack::EStkFOCMultiSel));
  1023 				idx = i;
  1024 				}
  1025 			}
  1026 
  1027 		__ASSERT_DEBUG(idx != -1, DWinsCPRMStack::Panic(DWinsCPRMStack::EStkFOCNoneSel));
  1028 		return idx;
  1029 		}
  1030 	}
  1031 
  1032 TMMCErr DWinsCPRMStack::CIMCalculateMediaKeySM()
  1033 //
  1034 // Calculate the Media Key record. 
  1035 //
  1036 	{
  1037   	enum states
  1038   		{
  1039   		EStBegin=0,
  1040   		EStEnd
  1041   		};
  1042 
  1043 	SMF_BEGIN
  1044 
  1045   	return( KMMCErrNotSupported );
  1046 
  1047 	SMF_END
  1048 	}
  1049 
  1050 TMMCErr DWinsCPRMStack::SetSecureCommandArgumentSM()
  1051 //
  1052 // Auxilary state machine function called during a secure read/write blocks operation.
  1053 // Perform random number generation and setting the secure command argument.
  1054 //
  1055 	{
  1056   	enum states
  1057   		{
  1058   		EStBegin=0,
  1059   		EStEnd
  1060   		};
  1061 
  1062 	SMF_BEGIN
  1063 
  1064   	return( KMMCErrNotSupported );
  1065 
  1066 	SMF_END
  1067 	}				  
  1068   
  1069 
  1070 // ======== DWinsMMCMediaChange ========
  1071 
  1072 #pragma warning( disable : 4355 )	// this used in initializer list
  1073 DWinsMMCMediaChange::DWinsMMCMediaChange(TInt aMediaChangeNum)
  1074 	: DMMCMediaChange(aMediaChangeNum),
  1075       iDoorClosedCount(0),
  1076 	  iMediaChangeEnable(ETrue),
  1077 	  iStackP(NULL)
  1078 	{
  1079 	iMediaDoorCloseReload=2; 	// Units: In theory-20ms, Actual-100ms
  1080 	}
  1081 #pragma warning( default : 4355 )
  1082 
  1083 TInt DWinsMMCMediaChange::Create()
  1084 //
  1085 // Initialiser.
  1086 //
  1087 	{	
  1088 	return(DMediaChangeBase::Create());
  1089 	}
  1090 
  1091 void DWinsMMCMediaChange::DoorOpenService()
  1092 //
  1093 // Handle the media change (this function, never postponed is called on media
  1094 // change interrupt). 
  1095 //
  1096 	{
  1097 	Disable();		// Disable interrupt until door closes again.
  1098 	iDoorOpenDfc.Enque();
  1099 	}
  1100 
  1101 void DWinsMMCMediaChange::DoDoorOpen()
  1102 //
  1103 // Handle media door open (called on media door open interrupt). 
  1104 //
  1105 	{
  1106 	iDoorClosedCount=iMediaDoorCloseReload;
  1107 	// Just start a ticklink to poll for door closing
  1108 	iTickLink.Periodic(KMediaChangeTickInterval,DWinsMMCMediaChange::Tick,this);
  1109     }
  1110 
  1111 void DWinsMMCMediaChange::DoDoorClosed()
  1112 //
  1113 // Handle media door closing (called on media door open interrupt).
  1114 //
  1115 	{
  1116 
  1117 	iTickLink.Cancel();	// Doesn't matter if wasn't enabled
  1118 	Enable();	// Re-enable door interrupts
  1119 
  1120 	// While the door was open the user may have changed the card in slot 0
  1121 	if (iStackP && *Wins::CurrentPBusDevicePtr()>=0)
  1122 		iStackP->iCardInfo[0]=iStackP->iCardPool[*Wins::CurrentPBusDevicePtr()];
  1123 	}
  1124 
  1125 void DWinsMMCMediaChange::ForceMediaChange()
  1126 //
  1127 // Force media change
  1128 //
  1129 	{
  1130 	DoorOpenService();
  1131 	}
  1132 
  1133 TMediaState DWinsMMCMediaChange::MediaState()
  1134 //
  1135 // Return status of media changed signal.
  1136 //
  1137 	{
  1138 
  1139 	if (iDoorClosedCount>0)
  1140 		return(EDoorOpen);
  1141 	return( (*Wins::MediaDoorOpenPtr())?EDoorOpen:EDoorClosed);
  1142 	}
  1143 
  1144 void DWinsMMCMediaChange::Tick(TAny *aPtr)
  1145 //
  1146 // Called on the tick to poll for door closing (called on DFC).
  1147 //
  1148 	{
  1149 
  1150 	((DWinsMMCMediaChange*)aPtr)->TickService();
  1151 	}
  1152 
  1153 void DWinsMMCMediaChange::TickService()
  1154 //
  1155 // Called on the tick to poll for door closing (called on DFC).
  1156 //
  1157 	{
  1158 
  1159 	__ASSERT_DEBUG(iDoorClosedCount>=0,DWinsCPRMStack::Panic(DWinsCPRMStack::EWinsMMCMediaChangeTickFault));
  1160 	if (!(*Wins::MediaDoorOpenPtr()))
  1161 		{
  1162 		if (iDoorClosedCount > 0)
  1163 			iDoorClosedCount--;
  1164 		if (iDoorClosedCount == 0)
  1165 			DoorClosedService();
  1166 		}
  1167 	else
  1168 		iDoorClosedCount=iMediaDoorCloseReload; // Door open so start again.
  1169 	}
  1170 
  1171 void DWinsMMCMediaChange::Enable()
  1172 //
  1173 // Enable media change 
  1174 //
  1175 	{
  1176 
  1177 	iMediaChangeEnable=ETrue;
  1178 	}
  1179 
  1180 void DWinsMMCMediaChange::Disable()
  1181 //
  1182 // Disable media change
  1183 //
  1184 	{
  1185 
  1186 	iMediaChangeEnable=EFalse;
  1187 	}
  1188 
  1189 void DWinsMMCMediaChange::MediaChangeCallBack(TAny *aPtr)
  1190 //
  1191 // Static called on media change
  1192 //
  1193 	{
  1194 
  1195 	DWinsMMCMediaChange* mc=(DWinsMMCMediaChange*)aPtr;
  1196 	if (mc!=NULL&&mc->iMediaChangeEnable)
  1197 		mc->DoorOpenService();
  1198 	}
  1199 
  1200 
  1201 // ======== TWinsCardInfo ========
  1202 
  1203 void TWinsCardInfo::GetCSD(TUint8* aResp) const
  1204 	{
  1205 	// Bits 127-96
  1206 	TUint32 csd=(0x1<<30); 	/* CSD_STRUCTURE: CSD Version No 1.1 */
  1207 	csd|=		(0x2<<26); 	/* SPEC_VERS: Version 2.1 */
  1208 	csd|=		(0x0E<<16);	/* TAAC: 1mS */  
  1209 	csd|=		(0x0A<<8);	/* NSAC: 1000 */  
  1210 	csd|=		(0x59);		/* TRAN_SPEED: 5.0Mbit/s */  
  1211 	TMMC::BigEndian4Bytes(&aResp[0],csd);
  1212 	// Bits 95-64
  1213 	const TUint32 ccc = 
  1214 			KMMCCmdClassBasic | KMMCCmdClassBlockRead
  1215 		|	KMMCCmdClassBlockWrite | KMMCCmdClassLockCard;
  1216 	csd=		(ccc<<20); 	/* CCC: classes 0, 2, 4, and 7 */
  1217 	csd|=		(0x9<<16); 	/* READ_BL_LEN: 512 bytes */
  1218 	csd|=		(0x0<<15);	/* READ_BL_PARTIAL: No */  
  1219 	csd|=		(0x0<<14);	/* WRITE_BLK_MISALIGN: No */  
  1220 	csd|=		(0x0<<13);	/* READ_BLK_MISALIGN: No */  
  1221 	csd|=		(0x0<<12);	/* DSR_IMP: No DSR */ 
  1222 	csd|=		(0x0<<8);	/* C_SIZE: 1Mb */
  1223 	csd|=		(0x7F);		/* C_SIZE: 1Mb (cont)*/  
  1224 	TMMC::BigEndian4Bytes(&aResp[4],csd); 
  1225 	// Bits 63-32
  1226 	csd=		(3UL<<30); 	/* C_SIZE: 2Mb (cont) */
  1227 	csd|=		(0x1<<27); 	/* VDD_R_CURR_MIN: 1mA */
  1228 	csd|=		(0x1<<24);	/* VDD_R_CURR_MAX: 5mA */  
  1229 	csd|=		(0x2<<21); 	/* VDD_W_CURR_MIN: 5mA */
  1230 	csd|=		(0x3<<18);	/* VDD_W_CURR_MAX: 25mA */  
  1231 	csd|=		(0x0<<15);	/* C_SIZE_MULT: 0 */  
  1232 	if (! iIsSDCard)
  1233 		{
  1234 		csd|=		(0x0<<10);	/* SECTOR_SIZE: 1 write block */  
  1235 		csd|=		(0x0<<5);	/* ERASE_GRP_SIZE: 1 sector */  
  1236 		csd|=		(0x0);		/* WP_GRP_SIZE: 1 erase group */  
  1237 		}
  1238 	else
  1239 		{
  1240 		csd |= (0x00 << (46 - 32));	// ERASE_BLK_EN
  1241 		csd |= (0x1f << (39 - 32));	// SECTOR_SIZE: 32 write blocks
  1242 		csd |= (0x00 << (32 - 32));	// WP_GRP_SIZE: 1 erase sector.
  1243 		}
  1244 	TMMC::BigEndian4Bytes(&aResp[8],csd); 
  1245 	// Bits 31-0
  1246 	csd=		(0x0<<31); 	/* WP_GRP_ENABLE: No */
  1247 	csd|=		(0x0<<29); 	/* DEFAULT_ECC: ? */
  1248 	csd|=		(0x3<<26);	/* R2W_FACTOR: 8 */  
  1249 	csd|=		(0x9<<22); 	/* WRITE_BL_LEN: 512 bytes */
  1250 	csd|=		(0x0<<21);	/* WRITE_BL_PARTIAL: No */  
  1251 	csd|=		(0x0<<15);	/* FILE_FORMAT_GRP: Hard disk */  
  1252 	csd|=		(0x0<<14);	/* COPY: original */  
  1253 	csd|=		(0x0<<13);	/* PERM_WRITE_PROTECT: No */  
  1254 	csd|=		(0x0<<12);	/* TMP_WRITE_PROTECT: No */  
  1255 	csd|=		(0x0<<10);	/* FILE_FORMAT: Hard disk */  
  1256 	csd|=		(0x0<<8);	/* ECC: None */  
  1257 	csd|=		(0x0<<1);	/* CRC: ? */  
  1258 	csd|=		(0x1);		/* not used */  
  1259 	TMMC::BigEndian4Bytes(&aResp[12],csd);
  1260 	}
  1261 
  1262 // ======== DWinsMMCPsu ========
  1263 
  1264 
  1265 DWinsMMCPsu::DWinsMMCPsu(TInt aVccNum, TInt aMcId)
  1266 	: DMMCPsu(aVccNum, aMcId)
  1267 	{}
  1268 
  1269 void DWinsMMCPsu::Init()
  1270 //
  1271 // Initialise the PSU
  1272 //
  1273     {
  1274 	// Nothing to do
  1275     }
  1276 
  1277 void DWinsMMCPsu::DoSetState(TPBusPsuState aState)
  1278 //
  1279 // Turn on/off the PSU. If it is possible to adjust the output voltage on this
  1280 // PSU then retreive the required voltage level from TMMCPsu::iVoltageSetting
  1281 // (which is in OCR register format).
  1282 //
  1283     {
  1284 
  1285     switch (aState)
  1286         {
  1287         case EPsuOff:
  1288             break;
  1289         case EPsuOnFull:
  1290             break;
  1291         case EPsuOnCurLimit:
  1292             break;
  1293         }
  1294     }
  1295 
  1296 TInt DWinsMMCPsu::VoltageInMilliVolts()
  1297 //
  1298 // Return the level of the PSU (in mV) or -ve if error.
  1299 //
  1300     {
  1301 
  1302     return(0);
  1303     }
  1304 
  1305 void DWinsMMCPsu::DoCheckVoltage()
  1306 //
  1307 // Check the voltage level of the PSU is as expected. Returns either KErrNone, KErrGeneral 
  1308 // to indicate the pass/fail state or KErrNotReady if the voltage check isn't complete.
  1309 //
  1310     {
  1311 
  1312 	ReceiveVoltageCheckResult(KErrNone);
  1313     }
  1314 
  1315 void DWinsMMCPsu::PsuInfo(TPBusPsuInfo &anInfo)
  1316 //
  1317 // Return machine info relating to the MMC PSU supply
  1318 //
  1319     {
  1320 
  1321 	anInfo.iVoltageSupported=0x00040000; // 3.0V (OCR reg. format).
  1322 	anInfo.iMaxCurrentInMicroAmps=0;
  1323 	anInfo.iVoltCheckInterval=0;
  1324 	anInfo.iVoltCheckMethod=EPsuChkComparator;
  1325     anInfo.iNotLockedTimeOut=0;  // Not enabled
  1326 	anInfo.iInactivityTimeOut=5; // 5 Seconds
  1327     }