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