os/boardsupport/emulator/emulatorbsp/specific/sdcard/sdcard3c/sdio/pp_sdio.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2003-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_sdio.h" 
    20 
    21 const TInt  KDiskSectorSize=512;
    22 
    23 const TInt KTotalMDiskSize=0x100000; // 1MB (if changing this then also change CSD response)
    24 
    25 // ======== Register Map ========
    26 
    27 typedef TInt (*TAccessFunction)(TInt aTargetCard, TInt aVal, TAny* aThis, TBool aRead, TUint8& aData);
    28 
    29 const TInt KIoMapEnd = 0xFFFFFFFF;
    30 
    31 struct SRegisterMapInfo
    32 	{
    33 public:
    34 	TUint32 iRegisterID;				// Unique ID
    35 	
    36 	const SRegisterMapInfo* iChildMapP; // Pointer to child register map
    37 	
    38 	TUint32 iAddress;					// Start Address
    39 	TUint32 iLength;					// Register Length in Bytes
    40 	
    41 	const TAny*	iDataP;					// Data for auto-access (may be NULL)
    42 	TAccessFunction iAccessFunction;	// Invoked when register is accessed
    43 	
    44 	TUint8 iFlags;						// Bitmap of RO(0), R/W(1) bits (8-bit only?)
    45 	};
    46 
    47 // ======== Card Information Structures =========
    48 
    49 
    50 
    51 const TUint32 KCommonCisPtr = 0x1010;
    52 const TUint32 KCommonCisLen = 0x70;
    53 
    54 LOCAL_D const TText8 CardCommonCis[KCommonCisLen] =
    55 	{
    56 //	0x20,0x04,0xc0,0x12,0x00,0x00,0x21,0x02,0x0c,0x00,0x22,0x06,0x00,0x00,0x01,0x32,
    57 //	0x00,0x00,0x91,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x32,0x01,0x00,0x48,0x41,
    58 //	0x47,0x49,0x57,0x41,0x52,0x41,0x20,0x53,0x59,0x53,0x2d,0x43,0x4f,0x4d,0x20,0x43,
    59 //	0x4f,0x2e,0x2c,0x4c,0x54,0x44,0x2e,0x00,0x48,0x53,0x2d,0x53,0x44,0x44,0x4b,0x2d,
    60 //	0x30,0x30,0x32,0x20,0x56,0x65,0x72,0x2e,0x50,0x61,0x6e,0x61,0x00,0x00,0xff,0xff,
    61 //	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    62 //	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    63 
    64 	0x20,0x04,0xc0,0x12,0x00,0x00,0x21,0x02,0x0c,0x00,0x22,0x04,0x00,0x00,0x01,0x2A/*79*/,
    65 	0x91,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x35,0x01,0x00,0x48,0x41,0x47,0x49,
    66 	0x57,0x41,0x52,0x41,0x20,0x53,0x59,0x53,0x2d,0x43,0x4f,0x4d,0x20,0x43,0x4f,0x2e,
    67 	0x2c,0x4c,0x54,0x44,0x2e,0x00,0x48,0x53,0x2d,0x53,0x44,0x44,0x4b,0x2d,0x30,0x30,
    68 	0x32,0x20,0x56,0x65,0x72,0x2e,0x50,0x61,0x6e,0x61,0x00,0x53,0x48,0x50,0x00,0xff,
    69 	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    70 	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
    71 	};
    72 
    73 const TUint32 KFn1CisPtr = 0x2000;
    74 const TUint32 KFn1CisLen = 0x40;
    75 
    76 LOCAL_D const TText8 Fn1Cis[KFn1CisLen] =
    77 	{
    78 	0x21,0x02,0x0c,0x00,0x22,0x24,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
    79 	0x00,0x03,0x00,0x02,0x00,0x00,0x3c,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,
    80 	0x00,0x00,0x00,0x00,0x2c,0x01,0xf4,0x01,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
    81 	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,
    82 	};
    83 
    84 const TUint32 KFn2CisPtr = 0x3000;
    85 const TUint32 KFn2CisLen = 0x40;
    86 
    87 LOCAL_D const TText8 Fn2Cis[KFn2CisLen] =
    88 	{
    89 	0x21,0x02,0x0c,0x00,0x22,0x24,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
    90 	0x00,0x03,0x40,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,
    91 	0x00,0x00,0x00,0x00,0xfa,0x00,0xc2,0x01,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
    92 	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    93 	};
    94 
    95 
    96 // ======== Card Common Control Registers =========
    97 
    98 TUint8 GCCCRRegSdioRevision			= 0x00;
    99 TUint8 GCCCRRegSdSpec				= 0x00;
   100 TUint8 GCCCRRegIoEnable				= 0x00;
   101 TUint8 GCCCRRegIoReady				= 0x00;
   102 TUint8 GCCCRRegIntEnable			= 0x00;
   103 TUint8 GCCCRRegIntPending			= 0x00;
   104 TUint8 GCCCRRegIoAbort				= 0x00;
   105 TUint8 GCCCRRegBusInterfaceControl	= 0x00;
   106 TUint8 GCCCRRegCardCapability		= 0x00;
   107 TUint8 GCCCRRegCisPtrLo				= (KCommonCisPtr & 0x0000FF);
   108 TUint8 GCCCRRegCisPtrMid			= (KCommonCisPtr & 0x00FF00) >> 8;
   109 TUint8 GCCCRRegCisPtrHi				= (KCommonCisPtr & 0xFF0000) >> 16;
   110 TUint8 GCCCRRegBusSuspend			= 0x00;
   111 TUint8 GCCCRRegFunctionSelect		= 0x00;
   112 TUint8 GCCCRRegExecFlags			= 0x00;
   113 TUint8 GCCCRRegReadyFlags			= 0x00;
   114 TUint8 GCCCRRegFN0BlockSizeLo		= 0x00;	// Initialises with 0x0000
   115 TUint8 GCCCRRegFN0BlockSizeHi		= 0x00;	// Initialises with 0x0000
   116 
   117 TUint8 GFunctionToEnable = 0x00;
   118 
   119 LOCAL_D const SRegisterMapInfo IoMapCCCR[] =
   120 	{
   121 		{KCCCRRegSdioRevision,		  NULL, 0x00, 0x01, &GCCCRRegSdioRevision,		  NULL, 0x00},
   122 		{KCCCRRegSdSpec,			  NULL, 0x01, 0x01, &GCCCRRegSdSpec,			  NULL, 0x00},
   123 		
   124 		{KCCCRRegIoEnable,			  NULL, 0x02, 0x01, NULL, DWinsSDIOStack::AccessIoEnable, 0x00},
   125 		
   126 		{KCCCRRegIoReady,			  NULL, 0x03, 0x01, &GCCCRRegIoReady,			  NULL, 0x00},
   127 		{KCCCRRegIntEnable,			  NULL, 0x04, 0x01, &GCCCRRegIntEnable,			  NULL, 0xFF},
   128 		{KCCCRRegIntPending,		  NULL, 0x05, 0x01, &GCCCRRegIntPending,		  NULL, 0x00},
   129 		{KCCCRRegIoAbort,			  NULL, 0x06, 0x01, &GCCCRRegIoAbort,			  NULL, 0xFF},
   130 		{KCCCRRegBusInterfaceControl, NULL, 0x07, 0x01, &GCCCRRegBusInterfaceControl, NULL, 0xFF},
   131 		{KCCCRRegCardCapability,	  NULL, 0x08, 0x01, &GCCCRRegCardCapability,	  NULL, 0x00},
   132 		{KCCCRRegCisPtrLo,			  NULL, 0x09, 0x01, &GCCCRRegCisPtrLo,			  NULL, 0x00},
   133 		{KCCCRRegCisPtrMid,			  NULL, 0x0a, 0x01, &GCCCRRegCisPtrMid,			  NULL, 0x00},
   134 		{KCCCRRegCisPtrHi,			  NULL, 0x0b, 0x01, &GCCCRRegCisPtrHi,			  NULL, 0x00},
   135 		{KCCCRRegBusSuspend,		  NULL, 0x0c, 0x01, &GCCCRRegBusSuspend,		  NULL, 0xFF},
   136 		{KCCCRRegFunctionSelect,	  NULL, 0x0d, 0x01, &GCCCRRegFunctionSelect,	  NULL, 0xFF},
   137 		{KCCCRRegExecFlags,			  NULL, 0x0e, 0x01, &GCCCRRegExecFlags,			  NULL, 0x00},
   138 		{KCCCRRegReadyFlags,		  NULL, 0x0f, 0x01, &GCCCRRegReadyFlags,		  NULL, 0x00},
   139 		{KCCCRRegFN0BlockSizeLo,	  NULL, 0x10, 0x01, &GCCCRRegFN0BlockSizeLo,	  NULL, 0x00},
   140 		{KCCCRRegFN0BlockSizeHi,	  NULL, 0x11, 0x01, &GCCCRRegFN0BlockSizeHi,	  NULL, 0x00},
   141 		{KIoMapEnd,					  NULL, 0,	  0,	NULL,						  NULL, 0xFF}
   142 	};
   143 
   144 
   145 // ======== Function Basic Register 1 =========
   146 
   147 TUint8 GFBR1RegInterfaceCode = KFBRRegSupportsCSA;
   148 TUint8 GFBR1RegExtendedCode  = 0x00;
   149 TUint8 GFBR1RegPowerFlags	 = 0x00;
   150 TUint8 GFBR1RegCisPtrLo		 = (KFn1CisPtr & 0x0000FF);
   151 TUint8 GFBR1RegCisPtrMid	 = (KFn1CisPtr & 0x00FF00) >> 8;
   152 TUint8 GFBR1RegCisPtrHi		 = (KFn1CisPtr & 0xFF0000) >> 16;
   153 TUint8 GFBR1RegIoBlockSizeLo = 0x00;
   154 TUint8 GFBR1RegIoBlockSizeHi = 0x00;
   155 
   156 TUint32 GFBR1RegCsaPtr = 0x00000000;
   157 
   158 LOCAL_D const SRegisterMapInfo IoMapFBR1[] =
   159 	{
   160 		{KFBRRegInterfaceCode, NULL, 0x100, 0x01, &GFBR1RegInterfaceCode, NULL, 0x00},
   161 		{KFBRRegExtendedCode,  NULL, 0x101, 0x01, &GFBR1RegExtendedCode,  NULL, 0x00},
   162 		{KFBRRegPowerFlags,	   NULL, 0x102, 0x01, &GFBR1RegPowerFlags,	  NULL, 0x00},
   163 		{KFBRRegCisPtrLo,	   NULL, 0x109, 0x01, &GFBR1RegCisPtrLo,	  NULL, 0x00},
   164 		{KFBRRegCisPtrMid,	   NULL, 0x10a, 0x01, &GFBR1RegCisPtrMid,	  NULL, 0x00},
   165 		{KFBRRegCisPtrHi,	   NULL, 0x10b, 0x01, &GFBR1RegCisPtrHi,	  NULL, 0x00},
   166 
   167 		{KFBRRegCsaPtrLo,	   NULL, 0x10c, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
   168 		{KFBRRegCsaPtrMid,	   NULL, 0x10d, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
   169 		{KFBRRegCsaPtrHi,	   NULL, 0x10e, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
   170 		{KFBRRegCsaWindow,	   NULL, 0x10f, 0x01, NULL, DWinsSDIOStack::AccessCsaWindow,  0xFF},
   171 		
   172 		{KFBRRegIoBlockSizeLo, NULL, 0x110, 0x01, &GFBR1RegIoBlockSizeLo, NULL, 0xFF},
   173 		{KFBRRegIoBlockSizeHi, NULL, 0x111, 0x01, &GFBR1RegIoBlockSizeHi, NULL, 0xFF},
   174 		{KIoMapEnd,			   NULL, 0,	    0,	  NULL,					  NULL, 0x00}
   175 	};
   176 
   177 // ======== Function Basic Register 2 ========
   178 
   179 TUint8 GFBR2RegInterfaceCode = KFBRRegSupportsCSA | ESdioFunctionTypeUART;
   180 TUint8 GFBR2RegExtendedCode  = 0x00;
   181 TUint8 GFBR2RegPowerFlags	 = 0x00;
   182 TUint8 GFBR2RegCisPtrLo		 = (KFn2CisPtr & 0x0000FF);
   183 TUint8 GFBR2RegCisPtrMid	 = (KFn2CisPtr & 0x00FF00) >> 8;
   184 TUint8 GFBR2RegCisPtrHi		 = (KFn2CisPtr & 0xFF0000) >> 16;
   185 TUint8 GFBR2RegIoBlockSizeLo = 0x00;
   186 TUint8 GFBR2RegIoBlockSizeHi = 0x00;
   187 
   188 TUint32 GFBR2RegCsaPtr = 0x00000000;
   189 
   190 LOCAL_D const SRegisterMapInfo IoMapFBR2[] =
   191 	{
   192 		{KFBRRegInterfaceCode, NULL, 0x200, 0x01, &GFBR2RegInterfaceCode, NULL, 0x00},
   193 		{KFBRRegExtendedCode,  NULL, 0x201, 0x01, &GFBR2RegExtendedCode,  NULL, 0x00},
   194 		{KFBRRegPowerFlags,	   NULL, 0x202, 0x01, &GFBR2RegPowerFlags,	  NULL, 0x00},
   195 		{KFBRRegCisPtrLo,	   NULL, 0x209, 0x01, &GFBR2RegCisPtrLo,	  NULL, 0x00},
   196 		{KFBRRegCisPtrMid,	   NULL, 0x20a, 0x01, &GFBR2RegCisPtrMid,	  NULL, 0x00},
   197 		{KFBRRegCisPtrHi,	   NULL, 0x20b, 0x01, &GFBR2RegCisPtrHi,	  NULL, 0x00},
   198 
   199 		{KFBRRegCsaPtrLo,	   NULL, 0x20c, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
   200 		{KFBRRegCsaPtrMid,	   NULL, 0x20d, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
   201 		{KFBRRegCsaPtrHi,	   NULL, 0x20e, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
   202 		{KFBRRegCsaWindow,	   NULL, 0x20f, 0x01, NULL, DWinsSDIOStack::AccessCsaWindow,  0xFF},
   203 		
   204 		{KFBRRegIoBlockSizeLo, NULL, 0x210, 0x01, &GFBR2RegIoBlockSizeLo, NULL, 0xFF},
   205 		{KFBRRegIoBlockSizeHi, NULL, 0x211, 0x01, &GFBR2RegIoBlockSizeHi, NULL, 0xFF},
   206 		{KIoMapEnd,			   NULL, 0,	    0,	  NULL,					  NULL, 0x00}
   207 	};
   208 
   209 // ======== Function Basic Register 1 =========
   210 
   211 const TInt KIoMapCCCR	   = 0;
   212 const TInt KIoMapFBR1	   = 1;
   213 const TInt KIoMapFBR2	   = 2;
   214 const TInt KIoMapCommonCis = 3;
   215 const TInt KIoMapFn1Cis	   = 4;
   216 const TInt KIoMapFn2Cis	   = 5;
   217 
   218 LOCAL_D const SRegisterMapInfo IoMapTop[] =
   219 	{
   220 		{KIoMapCCCR,	  IoMapCCCR, 0x00,			0xFF,		   NULL,		  NULL, 0x00},
   221 		{KIoMapFBR1,	  IoMapFBR1, 0x100,			0xFF,		   NULL,		  NULL, 0x00},		
   222 		{KIoMapFBR2,	  IoMapFBR2, 0x200,			0xFF,		   NULL,		  NULL, 0x00},
   223 		{KIoMapCommonCis, NULL,		 KCommonCisPtr, KCommonCisLen, CardCommonCis, NULL, 0x00},
   224 		{KIoMapFn1Cis,	  NULL,		 KFn1CisPtr,	KFn1CisLen,	   Fn1Cis,		  NULL, 0x00},
   225 		{KIoMapFn2Cis,	  NULL,		 KFn2CisPtr,	KFn2CisLen,	   Fn2Cis,		  NULL, 0x00},
   226 		{KIoMapEnd,		  NULL,		 0,				0,			   NULL,		  NULL, 0x00}
   227 	};
   228 
   229 const SRegisterMapInfo* FindIoEntryFromID(const SRegisterMapInfo* aIoMapP, TUint32 aID)
   230 	{
   231 	const SRegisterMapInfo* foundEntry = NULL;
   232 	
   233 	TInt currentEntry = 0;
   234 	
   235 	while((aIoMapP[currentEntry].iRegisterID != KIoMapEnd) && (foundEntry == NULL))
   236 		{
   237 		if(aIoMapP[currentEntry].iRegisterID == aID)
   238 			{
   239 			foundEntry = aIoMapP+currentEntry;
   240 			}
   241 		currentEntry++;
   242 		}
   243 
   244 	return(foundEntry);
   245 	}
   246 
   247 const SRegisterMapInfo* FindIoEntryFromAddress(const SRegisterMapInfo* aIoMapP, TUint32 aAddr)
   248 	{
   249 	const SRegisterMapInfo* foundEntry = NULL;
   250 	
   251 	TInt currentEntry = 0;
   252 	
   253 	while((aIoMapP[currentEntry].iRegisterID != KIoMapEnd) && (foundEntry == NULL))
   254 		{
   255 		const TUint32 startAddr = aIoMapP[currentEntry].iAddress;
   256 		const TUint32 endAddr   = startAddr + aIoMapP[currentEntry].iLength - 1;
   257 		
   258 		if((aAddr >= startAddr) && (aAddr <= endAddr))
   259 			{
   260 			if(aIoMapP[currentEntry].iChildMapP)
   261 				{
   262 				foundEntry = FindIoEntryFromAddress(aIoMapP[currentEntry].iChildMapP, aAddr);
   263 				}
   264 			else
   265 				{
   266 				foundEntry = aIoMapP+currentEntry;
   267 				}
   268 			}
   269 		currentEntry++;
   270 		}
   271 
   272 	return(foundEntry);
   273 	}
   274 
   275 
   276 
   277 // ======== error code conversion ========
   278 
   279 GLDEF_C TInt MapLastErrorEpoc()
   280 //
   281 // map an Win32 error code to Epoc32 value
   282 //
   283 	{
   284 	TInt res=KErrGeneral;
   285 	switch (GetLastError())
   286 		{
   287 		case ERROR_SHARING_VIOLATION : res=KErrAccessDenied; break;
   288 		case ERROR_LOCK_VIOLATION : res=KErrLocked; break;
   289 		case ERROR_FILE_NOT_FOUND: res=KErrNotFound; break;
   290 		case ERROR_PATH_NOT_FOUND: res=KErrPathNotFound; break;
   291 		case ERROR_ALREADY_EXISTS:
   292 		case ERROR_FILE_EXISTS:
   293 			res=KErrAlreadyExists;
   294 			break;
   295 		case ERROR_NOT_READY: res=KErrNotReady; break;
   296 		case ERROR_UNRECOGNIZED_VOLUME:
   297 		case ERROR_NOT_DOS_DISK:
   298 			res=KErrUnknown;
   299 			break;
   300 		case ERROR_UNRECOGNIZED_MEDIA: res=KErrCorrupt; break;
   301 		case ERROR_INVALID_NAME: res=KErrBadName; break;
   302 		case ERROR_NO_MORE_FILES: res=KErrEof; break;
   303 		}
   304 	return(res);
   305 	}
   306 
   307 GLDEF_C TMMCErr MapLastErrorMmc()
   308 //
   309 // map Win32 error to a TMMCErr error.
   310 //
   311 	{
   312 	DWORD r=GetLastError();
   313 	TInt res=KErrGeneral;
   314 	switch (r)
   315 		{
   316 		case ERROR_SHARING_VIOLATION:
   317 		case ERROR_LOCK_VIOLATION:
   318 			res=KMMCErrLocked;			// KErrLocked
   319 			break;
   320 		case ERROR_FILE_NOT_FOUND:
   321 		case ERROR_PATH_NOT_FOUND:
   322 			res=KMMCErrNotFound;		// KErrNotFound
   323 			break;
   324 		case ERROR_ALREADY_EXISTS:
   325 		case ERROR_FILE_EXISTS:
   326 			res=KMMCErrAlreadyExists;	// KErrAlreadyExists
   327 			break;
   328 		case ERROR_NOT_READY: res=KMMCErrNoCard; break;
   329 		case ERROR_UNRECOGNIZED_VOLUME:
   330 		case ERROR_NOT_DOS_DISK:
   331 			res=KMMCErrGeneral;			// KErrGeneral
   332 			break;
   333 		case ERROR_UNRECOGNIZED_MEDIA:
   334 		case ERROR_INVALID_NAME:
   335 		case ERROR_NO_MORE_FILES:
   336 			res=KMMCErrResponseCRC; 	// KErrCorrupt
   337 			break;
   338 		}
   339 	return(res);
   340 	}
   341 
   342 // ======== DWinsSDIOStack ========
   343 
   344 DWinsSDIOStack::DWinsSDIOStack(TInt aBus, DMMCSocket* aSocket)
   345   : DSDIOStack(aBus, aSocket),
   346 	iEnableTimer(&DWinsSDIOStack::EnableTimerCallback,this)
   347 	{	
   348 	iAddressedCard=KBroadcastToAllCards;
   349 //	iCMD42Failed=EFalse;
   350 	}
   351 
   352 
   353 TInt DWinsSDIOStack::Init()
   354 //
   355 // Allocate any resources. Only created once on kernel initialization so dont
   356 // worry about cleanup if it leaves.
   357 //
   358 	{
   359 	if((iCardArray = new TSDIOCardArray(this)) == NULL)
   360 		return KErrNoMemory;
   361 
   362 	TInt r=DMMCStack::Init();
   363 	if(r!=KErrNone)
   364 		return r;
   365 
   366 	DMediaChangeBase* pMCBase = MMCSocket()->iMediaChange;
   367 	static_cast<DWinsMMCMediaChange*>(pMCBase)->SetStackP(this);
   368 	Wins::SetMediaChangeCallBackPtr(DWinsMMCMediaChange::MediaChangeCallBack, (TAny*)pMCBase);
   369 
   370 	//
   371 	// Over time memory can become fragmented, and so it is not possible to
   372 	// allocate physically contiguous pages.  Therefore, the buffers for IO
   373 	// are allocated at startup.
   374 	//
   375 	// block and erase sector size characteristics depend on the specific
   376 	// card model, and so the initial values are estimates based on a typical
   377 	// card.  If these do not match the actual card's block size (or erase
   378 	// size, for SD,) then the media driver just gets a reduced or increased
   379 	// buffer area, and its efficiency varies accordingly.
   380 	//
   381 	// For the WINS implementation, fragmentation does not matter because
   382 	// DMA is not used.  The memory must still be allocated here so MEDMMC is
   383 	// able to use it.
   384 	//
   385 	// The constant calculations could be folded, but this illustrates how the
   386 	// values are derived.
   387 	//
   388 
   389 	// MMC - values from Hitachi 16Mb card, datasheet HB288016MM1
   390 
   391 	// minor buffer must contain enough space for MBR or block
   392 	const TUint mmcBlkSzLog2 = 9;				// READ_BLK_LEN and WRITE_BLK_LEN
   393 	const TUint mmcBlkSz = 1 << mmcBlkSzLog2;
   394 	const TInt mmcMinorBufLen = Max(KDiskSectorSize, mmcBlkSz);
   395 
   396 	const TInt KMinMMCBlocksInBuffer = 8;
   397 	const TInt mmcCchBufLen = KMinMMCBlocksInBuffer << mmcBlkSzLog2;
   398 
   399 	const TInt mmcTotalBufLen = mmcMinorBufLen + mmcCchBufLen;
   400 
   401 	// SDCard - values from 64Mb Panasonic RP-SD064
   402 
   403 	const TUint sdBlkSzLog2 = 9;				// READ_BL_LEN and WRITE_BLK_LEN
   404 	const TUint sdBlkSz = 1 << sdBlkSzLog2;
   405 	const TInt sdMinorBufLen = Max(KDiskSectorSize, sdBlkSz);
   406 
   407 	const TUint ss = 0x1f;						// SECTOR_SIZE, add 1 for sector count
   408 	const TInt KMinSDBlocksInBuffer = 8;
   409 	const TInt sdCchBufLen = Max(KMinSDBlocksInBuffer, ss + 1) << sdBlkSzLog2;
   410 
   411 	const TInt sdTotalBufLen = sdMinorBufLen + sdCchBufLen;
   412 
   413 	const TInt totalBufLen = Max(mmcTotalBufLen, sdTotalBufLen);
   414 
   415 	iMDBuf = reinterpret_cast<TUint8*>(Kern::Alloc(totalBufLen));
   416 	iMDBufLen = totalBufLen;
   417 
   418 	// initialize each card on the stack
   419 	TInt i;
   420 	for (i = 0; i < KTotalWinsCards; ++i)
   421 		{
   422 		TInt r = SetupSimulatedCard(i);
   423 		if (r != KErrNone)
   424 			return r;
   425 		}
   426 
   427 	// initialize pointers to currently present cards
   428 
   429 	// Slot zero can toggle between no card; card 0 and card 1.  The current state is
   430 	// determined by *Wins::CurrentPBusDevicePtr() and toggled by pressing F4 when F5
   431 	// (door open) is held down.  Because this function is only executed at startup,
   432 	// assume start with card zero.
   433 	iCardInfo[0] = iCardPool[0];
   434 	for (i = 1; i < KTotalWinsCardSlots; ++i)
   435 		{
   436 		iCardInfo[i]=iCardPool[i+1];
   437 		}
   438 
   439 	return KErrNone;
   440 	}
   441 
   442 void DWinsSDIOStack::MachineInfo(TMMCMachineInfo& aMachineInfo)
   443 	{
   444 	aMachineInfo.iTotalSockets=KTotalWinsCardSlots;
   445 	aMachineInfo.iTotalMediaChanges=0;  		// Not used at present
   446 	aMachineInfo.iTotalPrimarySupplies=0;		// Not used at present
   447 
   448 	aMachineInfo.iSPIMode=EFalse;
   449     aMachineInfo.iBaseBusNumber=0;
   450 
   451 	__ASSERT_DEBUG(aMachineInfo.iTotalSockets<=KMaxMMCardsPerStack,
   452 					DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCBadMachineInfo));
   453 	}
   454 
   455 void DWinsSDIOStack::AdjustPartialRead(
   456 #ifdef _DEBUG
   457 	const TMMCard* aCard,
   458 #else
   459 	const TMMCard* /*aCard*/,
   460 #endif
   461 	TUint32 aStart, TUint32 aEnd, TUint32* aPhysStart, TUint32* aPhysEnd) const
   462 	{
   463 #ifdef _DEBUG
   464 	const TUint32 blkLen = aCard->CSD().ReadBlockLength();
   465 	const TUint32 blkMsk = blkLen - 1;
   466 
   467 	__ASSERT_DEBUG(aCard->CSD().ReadBlPartial(), Panic(EWinsMMCAPRNotSupp));
   468 	__ASSERT_DEBUG(aEnd - aStart <= blkLen, Panic(EWinsMMCAPRRange));
   469 	__ASSERT_DEBUG((aEnd & ~blkMsk) > (aStart & ~blkMsk), Panic(EWinsMMCAPRBoundary));
   470 #endif
   471 
   472 	*aPhysStart = aStart & ~0x3;
   473 	*aPhysEnd = (aEnd + 0x3) & ~0x3;
   474 	}
   475 
   476 void DWinsSDIOStack::GetBufferInfo(TUint8** aMDBuf, TInt* aMDBufLen)
   477 	{
   478 	*aMDBuf = iMDBuf;
   479 	*aMDBufLen = iMDBufLen;
   480 	}
   481 
   482 void DWinsSDIOStack::Panic(TWinsMMCPanic aPanic)
   483 	{
   484 	_LIT(KPncNm,"PBUS-MMCSD-WINS");
   485 	Kern::PanicCurrentThread(KPncNm,aPanic);
   486 	}
   487 
   488 TInt DWinsSDIOStack::SetupSimulatedCard(TInt aCardNum)
   489 //
   490 // allocate individual card with Win32 file.  Only called at bootup, so no cleanup if fails.
   491 //
   492 	{
   493 	TWinsCardInfo* cip = new TWinsCardInfo;
   494 	if (cip == 0)
   495 		return KErrNoMemory;
   496 
   497 	TUint8 cid[KMMCCIDLength];
   498 	cid[0] = 'C';
   499 	cid[1] = 'I';
   500 	cid[2] = 'D';
   501 	cid[3] = TUint8('0' + aCardNum);
   502 	TInt j;
   503 	for (j = 4; j < KMMCCIDLength - 1; ++j)
   504 		cid[j] = 'c';
   505 	cid[KMMCCIDLength - 1] = '#';				// '#' = 0x23, bit zero must be 1
   506 	cip->iCID=cid;
   507 
   508 	cip->iPWD = new TMediaPassword;
   509 	if (! cip->iPWD)
   510 		{
   511 		delete cip;
   512 		return KErrNoMemory;
   513 		}
   514 
   515 	// cards in slot zero are SD
   516 	TInt mediaAreas;
   517 	if (aCardNum <= 1)
   518 		{
   519 		cip->iIsSDCard = ETrue;
   520 		mediaAreas = 3;	// +1 for SDIO area
   521 		}
   522 	else
   523 		{
   524 		cip->iIsSDCard = EFalse;
   525 		mediaAreas = 1;
   526 		}
   527 
   528 	cip->iState=ECardStateIdle;
   529 
   530 	for (TInt area = 0; area < mediaAreas; ++area)
   531 		{
   532 		TInt r = CreateBinFileForCard(aCardNum, area, &cip->iAreaHandles[area]);
   533 		if (r != KErrNone)
   534 			return r;
   535 		}
   536 	iCardPool[aCardNum]=cip;
   537 	return(KErrNone);
   538 	}
   539 
   540 TInt DWinsSDIOStack::CreateBinFileForCard(TInt aCardNum, TInt aAreaNum, HANDLE* aHandle)
   541 //
   542 // create .bin file in temp directory to contain media area of card.
   543 //
   544 	{
   545 	const char* emulatorPath = Property::GetString("EmulatorMediaPath");
   546 	if (!Emulator::CreateAllDirectories(emulatorPath))
   547 		return Emulator::LastError();
   548 
   549 	TBuf8<KMaxFileName> fn8(_L8(emulatorPath));
   550 	fn8.Append(_L8("MMCCRD"));
   551 	fn8.AppendNum(aCardNum);
   552 	fn8.Append('A'+aAreaNum);
   553 	fn8.Append(_L8(".BIN"));
   554 	fn8.Append('\0');
   555 
   556 	*aHandle = CreateFileA(
   557 		(LPCSTR) fn8.Ptr(),					// LPCSTR lpFileName,
   558 		GENERIC_READ | GENERIC_WRITE,		// DWORD dwDesiredAccess
   559 		FILE_SHARE_READ | FILE_SHARE_WRITE,	// DWORD dwShareMode
   560 		NULL,								// LPSECURITY_ATTRIBUTES lpSecurityAttributes
   561 		OPEN_ALWAYS,						// DWORD dwCreationDisposition
   562 		FILE_FLAG_RANDOM_ACCESS,			// DWORD dwFlagsAndAttributes
   563 		NULL);								// HANDLE hTemplateFile
   564 
   565 	if (*aHandle == INVALID_HANDLE_VALUE)
   566 	    return MapLastErrorEpoc();
   567 	
   568 	if (	SetFilePointer(*aHandle, KTotalMDiskSize, NULL, FILE_BEGIN) == 0xffffffffu
   569 		||	! SetEndOfFile(*aHandle) )
   570 		{
   571 		CloseHandle(*aHandle);
   572 	    return MapLastErrorEpoc();
   573 		}
   574 
   575 	return KErrNone;
   576 	}
   577 
   578 void DWinsSDIOStack::SetBusConfigDefaults(TMMCBusConfig& aConfig, TUint aClock)
   579 	{
   580 	const TUint KWinsMaxHwInterfaceClk=104000;
   581 	const TUint KWinsResponseTimeOut=6400;
   582 	const TUint KWinsDataTimeOut=40000;
   583 	const TUint KWinsBusyTimeOut=200000;
   584 
   585 	aConfig.iBusClock = (aClock > KWinsMaxHwInterfaceClk) ? KWinsMaxHwInterfaceClk : aClock;
   586 	aConfig.iResponseTimeOut=KWinsResponseTimeOut;
   587 	aConfig.iDataTimeOut=KWinsDataTimeOut;
   588 	aConfig.iBusyTimeOut=KWinsBusyTimeOut;
   589 	}
   590 
   591 void DWinsSDIOStack::InitClockOff()
   592 	{
   593 	// empty.
   594 	}
   595 
   596 void DWinsSDIOStack::ASSPReset()
   597 	{
   598 	// empty.
   599 	}
   600 
   601 void DWinsSDIOStack::ASSPDisengage()
   602 	{
   603 	// empty.
   604 	}
   605 
   606 void DWinsSDIOStack::DoPowerDown()
   607 	{
   608 	// empty.
   609 	}
   610 
   611 
   612 LOCAL_C TInt SetMediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,const TDesC8& aPasswd)
   613 // 
   614 // Set the password for local drive 'aLocalDrive', card number 'aCardNum' to 'aPasswd' - as an
   615 // environment variable. Note that the card number is only relevant where the emulated drive
   616 // supports card hot-swapping (i.e. F4 whilst F5 is held down).
   617 //
   618 	{
   619 	// Setup the appropriate environment variable string '_EPOC_LocDrv_<locDrvNum>_PWORD_<cardNum>'
   620 	TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
   621 
   622 	envVar[13]=(TUint16)('0'+aSocketNum);
   623 	envVar[21]=(TUint16)('0'+aCardNum);
   624 	
   625 	// Setup the new value of the environment variable
   626 	TUint16	envVal[100];
   627 	TInt len=aPasswd.Length();
   628 
   629 	// the password may be empty if a card's password is cleared
   630 	if (len>(100-1))
   631 		return(KErrArgument);
   632 	memcpy(&envVal[0],reinterpret_cast<const TUint16 *>(aPasswd.Ptr()),len);
   633 	envVal[len>>1]='\0';
   634 
   635 	// Now set the new value for the environment variable
   636 	if (SetEnvironmentVariable(envVar,&envVal[0]))
   637 		return(KErrNone);
   638 
   639 	return KErrGeneral;
   640 	}
   641 
   642 LOCAL_C TInt MediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,TDes8& aPasswd)
   643 // 
   644 // Get the password for local drive 'aLocalDrive', card number 'aCardNum' into 'aPasswd' - from
   645 // an environment variable. Note that the card number is only relevant where the emulated drive
   646 // supports card hot-swapping (i.e. F4 whilst F5 is held down).
   647 //
   648 	{
   649 	TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
   650 
   651 	envVar[13]=(TUint16)('0'+aSocketNum);
   652 	envVar[21]=(TUint16)('0'+aCardNum);
   653 	
   654 	TUint16 envVal[100];	// To hold the value of the retreived environment variable
   655 	
   656 	DWORD len=GetEnvironmentVariable(envVar,&envVal[0],100);
   657 	if (len>(TUint)100)
   658 		return(KErrGeneral);
   659 	if (len)
   660 		{
   661 		// Found the requested environment variable so there is a password for this local drive / card. 
   662 		if ((len<<1)<=KMaxMediaPassword)
   663 			{
   664 			aPasswd.FillZ(KMaxMediaPassword);
   665 			aPasswd.Zero();
   666 			aPasswd.Copy(reinterpret_cast<TUint8*>(&envVal[0]),len<<1);
   667 			return(KErrNone);	
   668 			}
   669 		else	
   670 			return(KErrGeneral);	
   671 		}
   672 
   673 	return(KErrNotFound);
   674 	}
   675 
   676 TMMCErr DWinsSDIOStack::DoPowerUpSM()
   677 	{
   678 	enum states
   679 		{
   680 		EStBegin=0,
   681 		EStEnd
   682 		};
   683 
   684 	SMF_BEGIN
   685 
   686 		if(MMCSocket()->iVcc->SetState(EPsuOnCurLimit) != KErrNone)
   687 			return KMMCErrHardware;
   688 
   689 		for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   690 			{
   691 			// if card has a password, it will be locked on power up
   692 			TInt cardNum = (i==0) ? *Wins::CurrentPBusDevicePtr() : i + 1;
   693 			if (	cardNum >= 0
   694 				&&	MediaPasswordEnvironmentVar(
   695 						MMCSocket()->iSocketNumber, cardNum, *(iCardInfo[i]->iPWD))
   696 					==	KErrNone)
   697 				{
   698 				iCardInfo[i]->iIsLocked = (iCardInfo[i]->iPWD->Length() > 0);
   699 				}
   700 			else	
   701 				iCardInfo[i]->iIsLocked=EFalse;
   702 
   703 			iCardInfo[i]->iState = ECardStateIdle;
   704 			iCardInfo[i]->iRCA=0x0001;		// Default RCA - spec 2.2, s4.2.1, 5.4
   705 			}
   706 
   707 		ReportPowerUp();
   708 
   709 	SMF_END
   710 	}
   711 
   712 TMMCErr DWinsSDIOStack::InitClockOnSM()
   713 	{
   714 	enum states
   715 		{
   716 		EStBegin=0,
   717 		EStEnd
   718 		};
   719 	SMF_BEGIN
   720 
   721 	SMF_END
   722 	}
   723 
   724 void DWinsSDIOStack::AddressCard(TInt aCardNumber)
   725 	{
   726 	iAddressedCard = aCardNumber;
   727 	}
   728 
   729 
   730 TInt DWinsSDIOStack::GetTargetSlotNumber(const TRCA& anRCA)
   731 //
   732 // when the controller is given a command with an embedded RCA, this function
   733 // works out which physical card slot it corresponds to.  If no card has been
   734 // assigned the RCA then it returns -1.
   735 //
   736 	{
   737 	TInt targetIdx = -1;
   738 
   739 	for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   740 		{
   741 		if (iCardInfo[i]->iRCA==anRCA)
   742 			{
   743 			targetIdx=i;
   744 			break;
   745 			}
   746 		}
   747 
   748 	return(targetIdx);
   749 	}
   750 
   751 TMMCErr DWinsSDIOStack::IssueMMCCommandSM()
   752 	{
   753 	enum states
   754 		{
   755 		EStBegin=0,
   756 		EStEnd
   757 		};
   758 
   759 	TMMCCommandDesc& cmd = Command();
   760 
   761 	// If the command contains an embedded RCA then extract it	
   762 	TRCA tgtRCA=0;
   763 	TBool supRCA=EFalse;
   764 	if (/*cmd.iCommand == ECmdSetRelativeAddr	||	*/cmd.iCommand == ECmdSelectCard
   765 	||	cmd.iCommand == ECmdSendCSD			||	cmd.iCommand == ECmdSendCID
   766 	||	cmd.iCommand == ECmdSendStatus		||	cmd.iCommand == ECmdGoInactiveState
   767 	||	cmd.iCommand == ECmdFastIO 			||  cmd.iCommand == ECmdAppCmd )
   768 		{
   769 		if ((cmd.iArgument >> 16) != 0)
   770 			{
   771 			supRCA=ETrue;
   772 			tgtRCA=TUint16(cmd.iArgument >> 16);
   773 			}
   774 		}
   775 
   776 	// if the card contains an embedded RCA, work out which slot it corresponds to.
   777 	// At the end of the function, this card is used to generate the R1 response.
   778 	// Assume that if rca is supplied it either corresponds to the selected card or
   779 	// broadcast mode is on.  (An exception is CMD7 with arg0 to deselect all cards.)
   780 
   781 	TInt targetCard = supRCA ? GetTargetSlotNumber(tgtRCA) : iAddressedCard;
   782 	TBool rto = EFalse;							// response timeout
   783 
   784 	// if try to access card zero has been set to holding no card via F5 / F4 then timeout.
   785 	if ((targetCard == 0) && *Wins::CurrentPBusDevicePtr() < 0)
   786 		return KMMCErrResponseTimeOut;
   787 	
   788 	HANDLE winHandle;
   789 
   790 	// CMD42 is a data transfer command.  That means the R1 response that it returns
   791 	// immediately is the state it is in on receiving the data block, and not after
   792 	// processing it.  If the data block is invalid then LOCK_UNLOCK_FAILED will be
   793 	// set in the R1 response which is sent in reply to the next command.
   794 
   795 	TBool nextCMD42Failed = EFalse;
   796 	TBool lock_unlock_failed=EFalse;
   797 
   798 	// When the card is locked, it will only respond to basic command class (0) and
   799 	// lock card command class (7).  An exception is CMD16.  This is sent before CMD42,
   800 	// but is classified (MMC Spec 23.2, table 5) as belonging to classes 2 and 4.
   801 	// For data transfer commands, LOCK_UNLOCK_FAIL is set in response to the following
   802 
   803 	TMMCCommandEnum origCmd = cmd.iCommand;
   804 
   805 	// if targetting locked card...
   806 	if (targetCard != KBroadcastToAllCards && iCardInfo[targetCard]->iIsLocked)
   807 		{
   808 		// ...and not command used in init or CMD42 sequence...
   809 		if (!(	((cmd.iSpec.iCommandClass & (KMMCCmdClassApplication | KMMCCmdClassBasic | KMMCCmdClassLockCard)) != 0)
   810 			||	(cmd.iCommand == ECmdSetBlockLen) || (cmd.iCommand == ECmdAppCmd) ))
   811 			{
   812 			lock_unlock_failed = ETrue;
   813 			cmd.iCommand = (TMMCCommandEnum) -1;	// skip case processing
   814 			}
   815 		}
   816 
   817 	SMF_BEGIN
   818 
   819 	switch (cmd.iCommand)
   820 		{
   821 		case ECmdGoIdleState:	// CMD0
   822 			if (iAddressedCard != KBroadcastToAllCards)
   823 				iCardInfo[iAddressedCard]->iState = ECardStateIdle;
   824 			else
   825 				{
   826 				for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   827 					iCardInfo[i]->iState = ECardStateIdle;
   828 				}
   829 			break;
   830 
   831 		case ECmd41:
   832 		case ECmdSendOpCond:	// CMD1
   833 			{
   834 			if (iAddressedCard != KBroadcastToAllCards)
   835 				iCardInfo[iAddressedCard]->iState = ECardStateReady;
   836 			else
   837 				{
   838 				for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
   839 					iCardInfo[i]->iState = ECardStateReady;
   840 				}
   841 
   842 			// bit31 is set to indicate cards are not still powering up
   843 			TUint32 r3 = KMMCWinsCardOCRValue | KMMCOCRBusy;
   844 			TMMC::BigEndian4Bytes(cmd.iResponse, r3);
   845 			}
   846 			break;
   847 
   848 		case ECmdAllSendCID:	// CMD2
   849 			{
   850 			TInt idx;
   851 			if (iAddressedCard != KBroadcastToAllCards)
   852 				{
   853 				idx = iAddressedCard;
   854 				__ASSERT_DEBUG(
   855 					iCardInfo[iAddressedCard]->iState == ECardStateReady,
   856 					DWinsSDIOStack::Panic(DWinsSDIOStack::EStkIMCBadStateCmd2));
   857 				}
   858 			else
   859 				idx = FindAnyCardInStack(ECardStateReady);
   860 
   861 			if (idx == -1)
   862 				rto = ETrue;
   863 			else
   864 				{
   865 				iCardInfo[idx]->iCID.Copy(cmd.iResponse);
   866 				iCardInfo[idx]->iState = ECardStateIdent;
   867 				}
   868 			}
   869 			break;
   870 
   871 		case ECmdSetRelativeAddr:	// CMD3
   872 			{
   873 			TInt idx;
   874 			if (iAddressedCard != KBroadcastToAllCards)
   875 				{
   876 				__ASSERT_DEBUG(
   877 					iCardInfo[iAddressedCard]->iState == ECardStateIdent,
   878 					DWinsSDIOStack::Panic(DWinsSDIOStack::EStkIMCBadStateCmd3));
   879 				
   880 				if (iCardInfo[iAddressedCard]->iIsSDCard)
   881 					{
   882 					static TUint16 RCACounter = 0x1234;
   883 					// SD Cards publish RCAs
   884 					++RCACounter;
   885 					iCardInfo[iAddressedCard]->iRCA = RCACounter;
   886 					iCardInfo[iAddressedCard]->iState = ECardStateStby;
   887 					TUint32 r6 = TUint32(RCACounter) << 16;
   888 					TMMC::BigEndian4Bytes(&cmd.iResponse[0],r6); // Ignore bits 47-40
   889 					}
   890 				else
   891 					{
   892 					iCardInfo[iAddressedCard]->iRCA = TUint16(cmd.iArgument >> 16);
   893 					iCardInfo[iAddressedCard]->iState=ECardStateStby;
   894 					}
   895 				}
   896 			else
   897 				{
   898 				// MultiMediaCards are assigned RCAs
   899 				idx = FindOneCardInStack(ECardStateIdent);
   900 				iCardInfo[iAddressedCard]->iRCA = TUint16(cmd.iArgument >> 16);
   901 				iCardInfo[iAddressedCard]->iState=ECardStateStby;
   902 				targetCard = iAddressedCard;
   903 				}
   904 			}
   905 			break;
   906 
   907 		case ECmd6:
   908 			// if ACMD6 then change bus width
   909 			if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
   910 				{
   911 				switch (cmd.iArgument)
   912 					{
   913 				case 0x00:
   914 					iCardInfo[iAddressedCard]->iBusWidth = 1;
   915 					break;
   916 				case 0x02:
   917 					iCardInfo[iAddressedCard]->iBusWidth = 4;
   918 					break;
   919 				default:
   920 					DWinsSDIOStack::Panic(DWinsSDIOStack::EStkIMCCmd6InvalidWidth);
   921 					break;
   922 					}
   923 				}
   924 			break;
   925 
   926 		case ECmdSelectCard:		// CMD7
   927 			{
   928 			// switch to broadcast mode so the currently selected and new cards
   929 			// receive the command simultaneously.
   930 
   931 			TInt idx = FindAnyCardInStack(ECardStateTran);
   932 			if (idx != -1)
   933 				iCardInfo[idx]->iState = ECardStateStby;
   934 			if ((iAddressedCard=targetCard) == KBroadcastToAllCards)
   935 				rto = ETrue;
   936 			else
   937 				{
   938 				iCardInfo[targetCard]->iState = ECardStateTran;
   939 				targetCard = targetCard;
   940 				}
   941 			}
   942 			break;
   943 
   944 		case ECmdSendStatus:
   945 			// R1 response so status return as for any other R1 command.
   946 			if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
   947 				{
   948 				__ASSERT_DEBUG(
   949 					iCardInfo[targetCard]->iIsSDCard,
   950 					DWinsSDIOStack::Panic(DWinsSDIOStack::EStkICMACMD13NotSD));
   951 
   952 				memset(cmd.iDataMemoryP, 0, KSDStatusBlockLength);
   953 				if (iCardInfo[targetCard]->iBusWidth == 1)
   954 					cmd.iDataMemoryP[0] = 0x00 << 6;
   955 				else	// if (iCardInfo[targetCard]->iBusWidth == 4)
   956 					cmd.iDataMemoryP[0] = 0x02 << 6;
   957 				cmd.iDataMemoryP[7] = 0x28;		// PROTECTED_AREA_SIZE
   958 				}
   959 			break;
   960 
   961 		case ECmdReadSingleBlock:
   962 		case ECmdReadMultipleBlock:
   963 			{
   964 			winHandle=iCardInfo[targetCard]->iAreaHandles[KSDUserArea];
   965 
   966 			if ( cmd.iSpec.iUseStopTransmission && cmd.iBlockLength >= cmd.iTotalLength)
   967 				return( KMMCErrNotSupported );
   968 
   969     		TMMCErr err;
   970 			TInt pos = cmd.iArgument;
   971     		if (SetFilePointer(winHandle,pos,NULL,FILE_BEGIN)==0xffffffffu)
   972         		err=MapLastErrorMmc();
   973     		else
   974         		{
   975 	    		DWORD res;
   976 				TInt len = cmd.iTotalLength;
   977 		        if (ReadFile(winHandle,(TAny*)cmd.iDataMemoryP,len,&res,NULL)==FALSE)
   978                     err=MapLastErrorMmc();
   979                 else if (res!=(DWORD)len)
   980                     err=KMMCErrGeneral;
   981                 else
   982                     err=KMMCErrNone;
   983 				}
   984 			if (err!=KMMCErrNone)
   985 				return(err);
   986 			break;
   987 			}
   988 
   989 		case ECmd22:
   990 			if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
   991 				{
   992 				TMMC::BigEndian4Bytes(cmd.iResponse, iMBWOKBlocks);
   993 				}
   994 			break;
   995 		// ------------------------------------------------------------------
   996 		case ECmdWriteBlock:
   997 		case ECmdWriteMultipleBlock:
   998 			{
   999 			TUint32 writeLen;
  1000 
  1001 			// periodically fail multi-block writes to test ACMD22 error recovery
  1002 			if (cmd.iCommand != ECmdWriteMultipleBlock)
  1003 				writeLen = cmd.iTotalLength;
  1004 			else
  1005 				{
  1006 				const TInt KMaxFailCnt = 4;
  1007 				static TInt failCnt = 0;
  1008 				const TInt KMaxFailBlock = 4;
  1009 				static TInt failBlocks = 0;
  1010 				
  1011 				failCnt = (failCnt + 1) % KMaxFailCnt;
  1012 				if (failCnt != 0)
  1013 					writeLen = cmd.iTotalLength;
  1014 				else
  1015 					{
  1016 					failBlocks = (failBlocks + 1) % KMaxFailBlock;
  1017 					
  1018 					// fail at least one block
  1019 					TInt totalBlocks = cmd.iTotalLength / cmd.iBlockLength;
  1020 					TInt blocksToFail = Min(failBlocks + 1, totalBlocks);	// fail at least one block
  1021 					iMBWOKBlocks = (totalBlocks - blocksToFail);
  1022 					writeLen = iMBWOKBlocks * cmd.iBlockLength;
  1023 					if (writeLen == 0)
  1024 						return KMMCErrDataTimeOut;
  1025 					}
  1026 				}
  1027 			
  1028 			HANDLE h=iCardInfo[targetCard]->iAreaHandles[KSDUserArea];
  1029 
  1030     		TMMCErr err;
  1031 			TInt pos = cmd.iArgument;
  1032     		if (SetFilePointer(h, pos, NULL, FILE_BEGIN)==0xffffffffu)
  1033         		err = MapLastErrorMmc();
  1034     		else
  1035         		{
  1036 	    		DWORD res;
  1037 				if (! WriteFile(h, (LPCVOID)cmd.iDataMemoryP,writeLen,&res,NULL))
  1038                     err=MapLastErrorMmc();
  1039                 else if (res!=(DWORD)writeLen)
  1040                     err=KMMCErrGeneral;
  1041                 else
  1042                     err=KMMCErrNone;
  1043 				}
  1044 
  1045 			if (err!=KMMCErrNone)
  1046 				return(err);
  1047 			if (writeLen != cmd.iTotalLength)
  1048 				return KMMCErrDataTimeOut;
  1049 			}
  1050 			break;
  1051 
  1052 		case ECmdAppCmd:
  1053 			// targetCard == -1 when ACMD41 being sent because not yet supplied
  1054 			if (iAddressedCard != KBroadcastToAllCards)
  1055 				{
  1056 				// timeout if addressed card is not SD
  1057 				if (! iCardInfo[iAddressedCard]->iIsSDCard)
  1058 					rto = ETrue;
  1059 				}
  1060 			else
  1061 				{
  1062 				// request sent to specific non-SD card
  1063 				if (targetCard != -1 && ! iCardInfo[targetCard]->iIsSDCard)
  1064 					rto = ETrue;
  1065 				}
  1066 			break;
  1067 
  1068 		case ECmdSendCSD:
  1069 			{
  1070 			iCardInfo[targetCard]->GetCSD(cmd.iResponse);
  1071 			break;
  1072 			}
  1073 
  1074 		// ------------------------------------------------------------------
  1075 		case ECmdLockUnlock:
  1076 			// in EPOC, Lock() does not actually lock the card.  It just sets the
  1077 			// password.  This means that the card is still accessible to the user,
  1078 			// but must be unlocked the next time it is powered up.
  1079 
  1080 			// a real card will transiently go into rcv and prg state while processing
  1081 			// this command.  When finished, it will fall back into tran state.
  1082 			// The R1 response is sent immediately after CMD42.  CIMReadWriteBlocksSM()
  1083 			// sends CMD13 to find out whether or not LOCK_UNLOCK_FAIL was set.
  1084 
  1085 			// the asserts in this case protect against invalid data being sent from the
  1086 			// media driver.  A real card would fail these corrupt data blocks.
  1087 
  1088 			{
  1089 			const TInt8 cmd_byte(*cmd.iDataMemoryP);
  1090 			__ASSERT_DEBUG(										// ensure not CLR_PWD && SET_PWD
  1091 				!((cmd_byte & KMMCLockUnlockClrPwd) && (cmd_byte & KMMCLockUnlockSetPwd)),
  1092 				DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCCorruptCommand) );
  1093 			
  1094 			__ASSERT_DEBUG(										// not actually lock a card
  1095 				!(cmd_byte & KMMCLockUnlockLockUnlock),
  1096 				DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCLockAttempt) );
  1097 
  1098 			if (cmd_byte & KMMCLockUnlockErase)					// ERASE (not supported)
  1099 				return KMMCErrNotSupported;
  1100 
  1101 			const TInt8 pwd_len = *(cmd.iDataMemoryP + 1);
  1102 			const TPtrC8 pwd(cmd.iDataMemoryP + 2, pwd_len);
  1103 
  1104 			if ((cmd_byte & KMMCLockUnlockClrPwd) != 0)			// CLR_PWD == 1
  1105 				{
  1106 				__ASSERT_DEBUG(
  1107 					pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
  1108 					DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCCorruptCommand));
  1109 
  1110 				if (iCardInfo[targetCard]->iIsLocked)						// clear when locked
  1111 					nextCMD42Failed = ETrue;
  1112 				else														// clear when unlocked
  1113 					{
  1114 					if (iCardInfo[targetCard]->iPWD->Compare(pwd) != 0)		// clear when unlocked with wrong password
  1115 						nextCMD42Failed = ETrue;
  1116 					else													// clear when unlocked with right password
  1117 						{
  1118 						// Clear from password store 
  1119 						iCardInfo[targetCard]->iPWD->Zero();
  1120 						iCardInfo[targetCard]->iIsLocked = EFalse;
  1121 						nextCMD42Failed = EFalse;
  1122 						
  1123 						// Clear from environment settings
  1124 						TInt cardNum=(targetCard==0) ? *Wins::CurrentPBusDevicePtr() : 0; // Can't be -1 at this stage
  1125 						SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[targetCard]->iPWD));
  1126 						}
  1127 					}
  1128 				}
  1129 			else if ((cmd_byte & KMMCLockUnlockSetPwd) == 0)	// SET_PWD == 0: unlock
  1130 				{
  1131 				__ASSERT_DEBUG(
  1132 					pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
  1133 					DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCCorruptCommand) );
  1134 				
  1135 				if (! iCardInfo[targetCard]->iIsLocked)						// unlock when unlocked
  1136 					nextCMD42Failed = ETrue;
  1137 				else
  1138 					{
  1139 					if (iCardInfo[targetCard]->iPWD->Compare(pwd) != 0)		// unlock when locked with wrong password
  1140 						nextCMD42Failed = ETrue;
  1141 					else													// unlock when locked with right password
  1142 						{
  1143 						iCardInfo[targetCard]->iIsLocked = EFalse;
  1144 						nextCMD42Failed = EFalse;
  1145 						}
  1146 					}
  1147 				}
  1148 			else /* ((cmd_byte & KMMCLockUnlockSetPwd) != 0) */	// SET_PWD == 1
  1149 				{
  1150 				__ASSERT_DEBUG(
  1151 					cmd_byte & KMMCLockUnlockSetPwd,
  1152 					DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCCorruptCommand) );
  1153 
  1154 				// if pwd_len < iCardInfo[targetCard]->iPWD->Length() then data block must be invalid.
  1155 				// This can be caused by bad user input rather than inaccurate formation.
  1156 				if (!(	pwd_len >= iCardInfo[targetCard]->iPWD->Length()
  1157 					&&	pwd_len <= iCardInfo[targetCard]->iPWD->Length() + KMaxMediaPassword ))
  1158 					{
  1159 					nextCMD42Failed = ETrue;
  1160 					}
  1161 				else
  1162 					{
  1163 					const TInt old_pwd_len = iCardInfo[targetCard]->iPWD->Length();
  1164 					TPtrC8 old_pwd(cmd.iDataMemoryP + 2, old_pwd_len);
  1165 					TPtrC8 new_pwd(cmd.iDataMemoryP + 2 + old_pwd_len, pwd_len - old_pwd_len);
  1166 
  1167 					// card must not be locked and supplied current password must be correct
  1168 					if (iCardInfo[targetCard]->iIsLocked || iCardInfo[targetCard]->iPWD->Compare(old_pwd) != 0)
  1169 						nextCMD42Failed = ETrue;
  1170 					else
  1171 						{
  1172 						// Set in password store
  1173 						iCardInfo[targetCard]->iPWD->Copy(new_pwd);
  1174 						nextCMD42Failed = EFalse;
  1175 						
  1176 						// Set in environment settings
  1177 						TInt cardNum=(targetCard==0) ? *Wins::CurrentPBusDevicePtr() : 0; // Can't be -1 at this stage
  1178 						SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[targetCard]->iPWD));
  1179 						}
  1180 					}
  1181 				}	// else /* ((cmd_byte & KMMCLockUnlockSetPwd) != 0) */
  1182 			}	// case ECmdLockUnlock
  1183 			break;
  1184 
  1185 		// ------------------------------------------------------------------
  1186 		case ECmd5:
  1187 			{
  1188 			if (!iCardInfo[iAddressedCard]->iIsSDCard)
  1189 				{
  1190 				rto = ETrue;
  1191 				}
  1192 			else
  1193 				{
  1194 				// bit31 is set to indicate cards are not still powering up
  1195 				TUint32 r5 = 0;
  1196 				
  1197 				r5 |= KWinsSdioFunctionCount << KSDIOFunctionCountShift;
  1198 				r5 |= KWinsSdioMemoryPresent ? KSDIOMemoryPresent : 0;
  1199 				r5 |= KMMCWinsCardOCRValue;
  1200 				r5 |= KSDIOReady;
  1201 
  1202 				TMMC::BigEndian4Bytes(cmd.iResponse, r5);
  1203 				}
  1204 			}
  1205 			break;
  1206 
  1207 		case ECmd52:
  1208 			{
  1209 			if (!iCardInfo[iAddressedCard]->iIsSDCard)
  1210 				{
  1211 				rto = ETrue;
  1212 				}
  1213 			else
  1214 				{
  1215 				const TUint32 address  = (cmd.iArgument >> KSdioCmdAddressShift)  & KSdioCmdAddressMask;
  1216 				const TUint32 function = (cmd.iArgument >> KSdioCmdFunctionShift) & KSdioCmdFunctionMask;
  1217 				
  1218 				const TUint32 ioAddress = address + (0x100*function);
  1219 
  1220 				const SRegisterMapInfo* entry = NULL;
  1221 				entry = FindIoEntryFromAddress(IoMapTop, ioAddress);
  1222 				
  1223 				if(!entry)
  1224 					{
  1225 					rto = ETrue;
  1226 					}
  1227 				else
  1228 					{
  1229 					if((cmd.iArgument & KSdioCmdDirMask) == KSdioCmdRead)
  1230 						{
  1231 						TUint8 dataVal = 0;
  1232 						if(entry->iAccessFunction)
  1233 							{
  1234 							entry->iAccessFunction(targetCard, entry->iRegisterID, this, ETrue, dataVal);
  1235 							}
  1236 						
  1237 						if(entry->iDataP)
  1238 							{
  1239 							TUint entryOffset = ioAddress - entry->iAddress;
  1240 							if(entryOffset >= 0 && entryOffset < entry->iLength)
  1241 								{
  1242 								dataVal = ((TUint8*)entry->iDataP)[entryOffset];
  1243 								}
  1244 							}
  1245 
  1246 						TUint32 r5 = 0;
  1247 
  1248 						r5 |= dataVal;
  1249 						r5 |= 0x1000;
  1250 
  1251 						TMMC::BigEndian4Bytes(cmd.iResponse, r5);
  1252 						}
  1253 					else
  1254 						{
  1255 						const TBool raw = (cmd.iArgument & KSdioCmdRAW) ? ETrue : EFalse;
  1256 						TUint8 data = (TUint8)(cmd.iArgument & KSdioCmdDataMask);
  1257 
  1258 						if(entry->iDataP)
  1259 							{
  1260 							*(TUint8*)(entry->iDataP) &= ~(entry->iFlags);
  1261 							*(TUint8*)(entry->iDataP) |= (data & entry->iFlags);
  1262 							}
  1263 						
  1264 						if(entry->iAccessFunction)
  1265 							{
  1266 							entry->iAccessFunction(targetCard, entry->iRegisterID, this, EFalse, data);
  1267 							}
  1268 						
  1269 						TUint32 r5 = 0;
  1270 							
  1271 						if(raw)
  1272 							{
  1273 							r5 |= data;
  1274 							}
  1275 
  1276 //						r5 |= 0x1000;
  1277 						r5 |= 0x2000;
  1278 
  1279 						TMMC::BigEndian4Bytes(cmd.iResponse, r5);
  1280 						}			
  1281 					}
  1282 				}
  1283 			}
  1284 			break;
  1285 
  1286 		case ECmd53:
  1287 			{
  1288 			TBool a = EFalse;
  1289 			if(a)
  1290 				{
  1291 				return(KMMCErrDataTimeOut);
  1292 				}
  1293 
  1294 			if (!iCardInfo[iAddressedCard]->iIsSDCard)
  1295 				{
  1296 				rto = ETrue;
  1297 				}
  1298 			else
  1299 				{
  1300 				const TUint32 address  = (cmd.iArgument >> KSdioCmdAddressShift)  & KSdioCmdAddressMask;
  1301 				const TUint32 function = (cmd.iArgument >> KSdioCmdFunctionShift) & KSdioCmdFunctionMask;
  1302 				
  1303 				const TUint32 ioAddress = address + (0x100*function);
  1304 
  1305 				if((cmd.iArgument & KSdioCmdBlockMode) == KSdioCmdBlockMode)
  1306 					{
  1307 					// Block mode not supported (yet)
  1308 					rto = ETrue;
  1309 					}
  1310 				else
  1311 					{
  1312 					TUint32 byteCount = cmd.iArgument & KSdioCmdCountMask;
  1313 					TUint32 count = 0;
  1314 					TUint32 currentAddress = ioAddress;
  1315 
  1316 					TUint32 inc = ((cmd.iArgument & KSdioCmdAutoInc) == KSdioCmdAutoInc) ? 1 : 0;
  1317 		
  1318 					while(count < byteCount)
  1319 						{
  1320 						const SRegisterMapInfo* entry = NULL;
  1321 						entry = FindIoEntryFromAddress(IoMapTop, currentAddress);
  1322 
  1323 						if(entry)
  1324 							{
  1325 							if((cmd.iArgument & KSdioCmdDirMask) == KSdioCmdRead)
  1326 								{
  1327 								TUint8 dataVal = 0;
  1328 								if(entry->iAccessFunction)
  1329 									{
  1330 									entry->iAccessFunction(targetCard, entry->iRegisterID, this, ETrue, dataVal);
  1331 									}
  1332 								
  1333 								if(entry->iDataP)
  1334 									{
  1335 									TUint entryOffset = currentAddress - entry->iAddress;
  1336 									if(entryOffset >= 0 && entryOffset < entry->iLength)
  1337 										{
  1338 										dataVal = ((TUint8*)entry->iDataP)[entryOffset];
  1339 										}
  1340 									}
  1341 
  1342 								cmd.iDataMemoryP[count] = dataVal;
  1343 								}
  1344 							else
  1345 								{
  1346 								TUint8 data = cmd.iDataMemoryP[count];
  1347 
  1348 								if(entry->iDataP)
  1349 									{
  1350 									TUint entryOffset = currentAddress - entry->iAddress;
  1351 									if(entryOffset >= 0 && entryOffset < entry->iLength)
  1352 										{
  1353 										((TUint8*)entry->iDataP)[entryOffset] &= ~(entry->iFlags);
  1354 										((TUint8*)entry->iDataP)[entryOffset] |= (data & entry->iFlags);
  1355 										}
  1356 
  1357 									}
  1358 								
  1359 								if(entry->iAccessFunction)
  1360 									{
  1361 									entry->iAccessFunction(targetCard, entry->iRegisterID, this, EFalse, data);
  1362 									}								
  1363 								}			
  1364 							}
  1365 							
  1366 							count++;
  1367 							currentAddress += inc;
  1368 						}
  1369 
  1370 						TUint32 r5 = 0;
  1371 						
  1372 //						r5 |= 0x2000;
  1373 						r5 |= 0x1000;
  1374 
  1375 						TMMC::BigEndian4Bytes(cmd.iResponse, r5);
  1376 					}
  1377 				}
  1378 			}
  1379 			break;
  1380 
  1381 		// ------------------------------------------------------------------
  1382 		default:
  1383 			break;
  1384 		}
  1385 
  1386 	if (rto)
  1387 		return(KMMCErrResponseTimeOut);
  1388 
  1389 	cmd.iCommand = origCmd;
  1390 	// If this is an R1 or R1b response type command then return card status as a response
  1391 	if (	targetCard != -1
  1392 		&&	(cmd.iSpec.iResponseType==ERespTypeR1 || cmd.iSpec.iResponseType==ERespTypeR1B) )
  1393 		{
  1394 		TUint32 resp(
  1395 				iCardInfo[targetCard]->iState
  1396 			|	((iCardInfo[targetCard]->iIsLocked ? 1 : 0) << 25)
  1397 			|	((lock_unlock_failed ? 1 : 0) << 24) );
  1398 
  1399 		if (iCMD42Failed)								// previous CMD42
  1400 			{
  1401 			resp |= KMMCStatErrLockUnlock;
  1402 			nextCMD42Failed = EFalse;
  1403 			}
  1404 		iCMD42Failed = nextCMD42Failed;
  1405 		TMMC::BigEndian4Bytes(&cmd.iResponse[0],resp); // Ignore bits 47-40
  1406 		}
  1407 	SMF_END
  1408 	}
  1409 
  1410 TInt DWinsSDIOStack::AccessIoEnable(TInt /*aTargetCard*/, TInt /*aVal*/, TAny* aSelfP, TBool aRead, TUint8& aData)
  1411 //
  1412 // Access the IO Enable register
  1413 //
  1414 	{
  1415 	DWinsSDIOStack& self = *(DWinsSDIOStack*)aSelfP;
  1416 	
  1417 	if(aRead)
  1418 		{
  1419 		aData = GCCCRRegIoEnable;
  1420 		}
  1421 	else
  1422 		{
  1423 		TUint8 mask = 0;
  1424 		for(TInt i=0; i<KWinsSdioFunctionCount; i++)
  1425 			{
  1426 			mask |= (0x02 << i);
  1427 			}
  1428 
  1429 		aData &= mask;
  1430 
  1431 		// Disable functions first...
  1432 		GFunctionToEnable &= aData;
  1433 		GCCCRRegIoReady   &= aData;
  1434 		GCCCRRegIoEnable  &= aData;
  1435 		
  1436 		// Enabling any functions - This uses the delayed timer...
  1437 		if((GCCCRRegIoEnable & aData) != aData)
  1438 			{
  1439 			GFunctionToEnable = GCCCRRegIoEnable ^ aData;
  1440 			GCCCRRegIoEnable |= GFunctionToEnable;
  1441 
  1442 			self.iEnableTimer.OneShot(KFunctionEnableDelay_uS / NKern::TickPeriod());
  1443 			}
  1444 		}
  1445 
  1446 	return(KErrNone);
  1447 	}
  1448 
  1449 void DWinsSDIOStack::EnableTimerCallback(TAny* /*aSelfP*/)
  1450 	{
  1451 	GCCCRRegIoReady |= GFunctionToEnable;
  1452 	}
  1453 
  1454 TInt DWinsSDIOStack::AccessCsaWindow(TInt aTargetCard, TInt /*aVal*/, TAny* aSelfP, TBool aRead, TUint8& aData)
  1455 //
  1456 // Access the CSA Windoe
  1457 //
  1458 	{
  1459 	TMMCErr err = KErrNone;
  1460 
  1461 	DWinsSDIOStack& self = *(DWinsSDIOStack*)aSelfP;
  1462 	
  1463 	HANDLE winHandle = self.iCardInfo[aTargetCard]->iAreaHandles[KSDIOArea];
  1464 
  1465     if (SetFilePointer(winHandle, GFBR1RegCsaPtr, NULL,FILE_BEGIN) == 0xffffffffu)
  1466         err = MapLastErrorMmc();
  1467     else
  1468         {
  1469 	    DWORD res;
  1470 		TUint8 val = 0;
  1471 		TUint len = 1;
  1472 		
  1473 		BOOL rwRes = FALSE;
  1474 
  1475 		if(aRead)
  1476 			{
  1477 			rwRes = ReadFile(winHandle, (TAny*)&val, len, &res, NULL);
  1478 			}
  1479 		else
  1480 			{
  1481 			val = aData;
  1482 			rwRes = WriteFile(winHandle, (TAny*)&val, len, &res, NULL);
  1483 			}
  1484 
  1485 		if(rwRes == FALSE)
  1486 			{
  1487             err = MapLastErrorMmc();
  1488 			}
  1489         else if(res != len)
  1490 			{
  1491             err = KMMCErrGeneral;
  1492 			}
  1493         else
  1494 			{
  1495 			if(aRead)
  1496 				{
  1497 				aData = val;
  1498 				}
  1499 
  1500 			GFBR1RegCsaPtr++;
  1501             err = KMMCErrNone;
  1502 			}
  1503 		}
  1504 
  1505 	return(err);
  1506 	}
  1507 
  1508 TInt DWinsSDIOStack::AccessCsaPointer(TInt /*aTargetCard*/, TInt aVal, TAny* /*aSelfP*/, TBool aRead, TUint8& aData)
  1509 //
  1510 // Access the CSA Windoe
  1511 //
  1512 	{
  1513 	TInt err = KErrNone;
  1514 
  1515 	TUint32 mask  = 0;
  1516 	TUint32 shift = 0;
  1517 
  1518 	switch(aVal)
  1519 		{
  1520 		case KFBRRegCsaPtrLo:
  1521 			{
  1522 			mask  = 0x0000FF;
  1523 			shift = 0;
  1524 			break;
  1525 			}
  1526 
  1527 		case KFBRRegCsaPtrMid:
  1528 			{
  1529 			mask  = 0x00FF00;
  1530 			shift = 8;
  1531 			break;
  1532 			}
  1533 
  1534 		case KFBRRegCsaPtrHi:
  1535 			{
  1536 			mask  = 0xFF0000;
  1537 			shift = 16;
  1538 			break;
  1539 			}
  1540 
  1541 		default:
  1542 			{
  1543 			err = KErrNotSupported;
  1544 			break;
  1545 			}
  1546 		}
  1547 
  1548 	if(err == KErrNone)
  1549 		{
  1550 		if(aRead)
  1551 			{
  1552 			aData = (TUint8)((GFBR1RegCsaPtr & mask) >> shift);
  1553 			}
  1554 		else
  1555 			{
  1556 			GFBR1RegCsaPtr &= ~mask;
  1557 			GFBR1RegCsaPtr |= (TUint32)aData << shift;
  1558 			}
  1559 		}
  1560 	
  1561 	return(err);
  1562 	}
  1563 
  1564 void DWinsSDIOStack::EnableSDIOInterrupt(TBool /*aEnable*/)
  1565 //
  1566 // Virtual
  1567 //
  1568 	{
  1569 	}
  1570 
  1571 void DWinsSDIOStack::SetBusWidth(TUint32 /*aBusWidth*/)
  1572 //
  1573 // Virtual
  1574 //
  1575 	{
  1576 	}
  1577 
  1578 TUint32 DWinsSDIOStack::MaxBlockSize() const
  1579 //
  1580 // Virtual
  1581 //
  1582 	{
  1583 	return(512);
  1584 	}
  1585 
  1586 
  1587 TInt DWinsSDIOStack::FindAnyCardInStack(TMMCardStateEnum aState)
  1588 //
  1589 // first first active card in supplied state.  Return -1 if
  1590 // no active card is in supplied state.
  1591 //
  1592 	{
  1593 	if (iAddressedCard != KBroadcastToAllCards)
  1594 		return (iCardInfo[iAddressedCard]->iState == aState) ? iAddressedCard : -1;
  1595 	else
  1596 		{
  1597 		for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
  1598 			{
  1599 			if (iCardInfo[i]->iState == aState)
  1600 				return i;
  1601 			}
  1602 
  1603 		return -1;
  1604 		}
  1605 	}
  1606 
  1607 TInt DWinsSDIOStack::FindFirstCardInStack(TMMCardStateEnum aState)
  1608 //
  1609 // find card which is active on bus and in supplied state.
  1610 // There can be more than one active card in the the supplied state,
  1611 // but there should be at least one.
  1612 //
  1613 	{
  1614 	if (iAddressedCard != KBroadcastToAllCards)
  1615 		{
  1616 		__ASSERT_DEBUG(iCardInfo[iAddressedCard]->iState == aState, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFFCNotSelCard));
  1617 		return iAddressedCard;
  1618 		}
  1619 	else
  1620 		{
  1621 		TInt idx = -1;
  1622 		for (TInt i = 0; idx != -1 && i < KTotalWinsCardSlots; ++i)
  1623 			{
  1624 			if (iCardInfo[i]->iState == aState)
  1625 				idx = i;
  1626 			}
  1627 
  1628 		__ASSERT_DEBUG(idx != -1, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFFCNoneSel));
  1629 		return idx;
  1630 		}
  1631 	}
  1632 
  1633 TInt DWinsSDIOStack::FindOneCardInStack(TMMCardStateEnum aState)
  1634 //
  1635 // find card which is active on bus and in supplied state.
  1636 // There should be exactly one active card in the supplied state.
  1637 //
  1638 	{
  1639 	if (iAddressedCard != KBroadcastToAllCards)
  1640 		{
  1641 		__ASSERT_DEBUG(iCardInfo[iAddressedCard]->iState == aState, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFOCNotSelCard));
  1642 		return iAddressedCard;
  1643 		}
  1644 	else
  1645 		{
  1646 		TInt idx = -1;
  1647 		for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
  1648 			{
  1649 			if (iCardInfo[i]->iState == aState)
  1650 				{
  1651 				__ASSERT_DEBUG(idx == -1, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFOCMultiSel));
  1652 				idx = i;
  1653 				}
  1654 			}
  1655 
  1656 		__ASSERT_DEBUG(idx != -1, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFOCNoneSel));
  1657 		return idx;
  1658 		}
  1659 	}
  1660 
  1661 
  1662 // ======== DWinsMMCMediaChange ========
  1663 
  1664 #pragma warning( disable : 4355 )	// this used in initializer list
  1665 DWinsMMCMediaChange::DWinsMMCMediaChange(TInt aMediaChangeNum)
  1666 	: DMMCMediaChange(aMediaChangeNum),
  1667       iDoorClosedCount(0),
  1668 	  iMediaChangeEnable(ETrue),
  1669 	  iStackP(NULL)
  1670 	{
  1671 	iMediaDoorCloseReload=2; 	// Units: In theory-20ms, Actual-100ms
  1672 	}
  1673 #pragma warning( default : 4355 )
  1674 
  1675 TInt DWinsMMCMediaChange::Create()
  1676 //
  1677 // Initialiser.
  1678 //
  1679 	{	
  1680 	return(DMediaChangeBase::Create());
  1681 	}
  1682 
  1683 void DWinsMMCMediaChange::DoorOpenService()
  1684 //
  1685 // Handle the media change (this function, never postponed is called on media
  1686 // change interrupt). 
  1687 //
  1688 	{
  1689 	Disable();		// Disable interrupt until door closes again.
  1690 	iDoorOpenDfc.Enque();
  1691 	}
  1692 
  1693 void DWinsMMCMediaChange::DoDoorOpen()
  1694 //
  1695 // Handle media door open (called on media door open interrupt). 
  1696 //
  1697 	{
  1698 	iDoorClosedCount=iMediaDoorCloseReload;
  1699 	// Just start a ticklink to poll for door closing
  1700 	iTickLink.Periodic(KMediaChangeTickInterval,DWinsMMCMediaChange::Tick,this);
  1701     }
  1702 
  1703 void DWinsMMCMediaChange::DoDoorClosed()
  1704 //
  1705 // Handle media door closing (called on media door open interrupt).
  1706 //
  1707 	{
  1708 
  1709 	iTickLink.Cancel();	// Doesn't matter if wasn't enabled
  1710 	Enable();	// Re-enable door interrupts
  1711 
  1712 	// While the door was open the user may have changed the card in slot 0
  1713 	if (iStackP && *Wins::CurrentPBusDevicePtr()>=0)
  1714 		iStackP->iCardInfo[0]=iStackP->iCardPool[*Wins::CurrentPBusDevicePtr()];
  1715 	}
  1716 
  1717 void DWinsMMCMediaChange::ForceMediaChange()
  1718 //
  1719 // Force media change
  1720 //
  1721 	{
  1722 	DoorOpenService();
  1723 	}
  1724 
  1725 TMediaState DWinsMMCMediaChange::MediaState()
  1726 //
  1727 // Return status of media changed signal.
  1728 //
  1729 	{
  1730 
  1731 	if (iDoorClosedCount>0)
  1732 		return(EDoorOpen);
  1733 	return( (*Wins::MediaDoorOpenPtr())?EDoorOpen:EDoorClosed);
  1734 	}
  1735 
  1736 void DWinsMMCMediaChange::Tick(TAny *aPtr)
  1737 //
  1738 // Called on the tick to poll for door closing (called on DFC).
  1739 //
  1740 	{
  1741 
  1742 	((DWinsMMCMediaChange*)aPtr)->TickService();
  1743 	}
  1744 
  1745 void DWinsMMCMediaChange::TickService()
  1746 //
  1747 // Called on the tick to poll for door closing (called on DFC).
  1748 //
  1749 	{
  1750 
  1751 	__ASSERT_DEBUG(iDoorClosedCount>=0,DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCMediaChangeTickFault));
  1752 	if (!(*Wins::MediaDoorOpenPtr()))
  1753 		{
  1754 		if (iDoorClosedCount > 0)
  1755 			iDoorClosedCount--;
  1756 		if (iDoorClosedCount == 0)
  1757 			DoorClosedService();
  1758 		}
  1759 	else
  1760 		iDoorClosedCount=iMediaDoorCloseReload; // Door open so start again.
  1761 	}
  1762 
  1763 void DWinsMMCMediaChange::Enable()
  1764 //
  1765 // Enable media change 
  1766 //
  1767 	{
  1768 
  1769 	iMediaChangeEnable=ETrue;
  1770 	}
  1771 
  1772 void DWinsMMCMediaChange::Disable()
  1773 //
  1774 // Disable media change
  1775 //
  1776 	{
  1777 
  1778 	iMediaChangeEnable=EFalse;
  1779 	}
  1780 
  1781 void DWinsMMCMediaChange::MediaChangeCallBack(TAny *aPtr)
  1782 //
  1783 // Static called on media change
  1784 //
  1785 	{
  1786 
  1787 	DWinsMMCMediaChange* mc=(DWinsMMCMediaChange*)aPtr;
  1788 	if (mc!=NULL&&mc->iMediaChangeEnable)
  1789 		mc->DoorOpenService();
  1790 	}
  1791 
  1792 
  1793 // ======== TWinsCardInfo ========
  1794 
  1795 void TWinsCardInfo::GetCSD(TUint8* aResp) const
  1796 	{
  1797 	// Bits 127-96
  1798 	TUint32 csd=(0x1<<30); 	/* CSD_STRUCTURE: CSD Version No 1.1 */
  1799 	csd|=		(0x2<<26); 	/* SPEC_VERS: Version 2.1 */
  1800 	csd|=		(0x0E<<16);	/* TAAC: 1mS */  
  1801 	csd|=		(0x0A<<8);	/* NSAC: 1000 */  
  1802 	csd|=		(0x59);		/* TRAN_SPEED: 5.0Mbit/s */  
  1803 	TMMC::BigEndian4Bytes(&aResp[0],csd);
  1804 	// Bits 95-64
  1805 	const TUint32 ccc = 
  1806 			KMMCCmdClassBasic | KMMCCmdClassBlockRead
  1807 		|	KMMCCmdClassBlockWrite | KMMCCmdClassLockCard;
  1808 	csd=		(ccc<<20); 	/* CCC: classes 0, 2, 4, and 7 */
  1809 	csd|=		(0x9<<16); 	/* READ_BL_LEN: 512 bytes */
  1810 	csd|=		(0x0<<15);	/* READ_BL_PARTIAL: No */  
  1811 	csd|=		(0x0<<14);	/* WRITE_BLK_MISALIGN: No */  
  1812 	csd|=		(0x0<<13);	/* READ_BLK_MISALIGN: No */  
  1813 	csd|=		(0x0<<12);	/* DSR_IMP: No DSR */ 
  1814 	csd|=		(0x0<<8);	/* C_SIZE: 1Mb */
  1815 	csd|=		(0x7F);		/* C_SIZE: 1Mb (cont)*/  
  1816 	TMMC::BigEndian4Bytes(&aResp[4],csd); 
  1817 	// Bits 63-32
  1818 	csd=		(3UL<<30); 	/* C_SIZE: 2Mb (cont) */
  1819 	csd|=		(0x1<<27); 	/* VDD_R_CURR_MIN: 1mA */
  1820 	csd|=		(0x1<<24);	/* VDD_R_CURR_MAX: 5mA */  
  1821 	csd|=		(0x2<<21); 	/* VDD_W_CURR_MIN: 5mA */
  1822 	csd|=		(0x3<<18);	/* VDD_W_CURR_MAX: 25mA */  
  1823 	csd|=		(0x0<<15);	/* C_SIZE_MULT: 0 */  
  1824 	if (! iIsSDCard)
  1825 		{
  1826 		csd|=		(0x0<<10);	/* SECTOR_SIZE: 1 write block */  
  1827 		csd|=		(0x0<<5);	/* ERASE_GRP_SIZE: 1 sector */  
  1828 		csd|=		(0x0);		/* WP_GRP_SIZE: 1 erase group */  
  1829 		}
  1830 	else
  1831 		{
  1832 		csd |= (0x00 << (46 - 32));	// ERASE_BLK_EN
  1833 		csd |= (0x1f << (39 - 32));	// SECTOR_SIZE: 32 write blocks
  1834 		csd |= (0x00 << (32 - 32));	// WP_GRP_SIZE: 1 erase sector.
  1835 		}
  1836 	TMMC::BigEndian4Bytes(&aResp[8],csd); 
  1837 	// Bits 31-0
  1838 	csd=		(0x0<<31); 	/* WP_GRP_ENABLE: No */
  1839 	csd|=		(0x0<<29); 	/* DEFAULT_ECC: ? */
  1840 	csd|=		(0x3<<26);	/* R2W_FACTOR: 8 */  
  1841 	csd|=		(0x9<<22); 	/* WRITE_BL_LEN: 512 bytes */
  1842 	csd|=		(0x0<<21);	/* WRITE_BL_PARTIAL: No */  
  1843 	csd|=		(0x0<<15);	/* FILE_FORMAT_GRP: Hard disk */  
  1844 	csd|=		(0x0<<14);	/* COPY: original */  
  1845 	csd|=		(0x0<<13);	/* PERM_WRITE_PROTECT: No */  
  1846 	csd|=		(0x0<<12);	/* TMP_WRITE_PROTECT: No */  
  1847 	csd|=		(0x0<<10);	/* FILE_FORMAT: Hard disk */  
  1848 	csd|=		(0x0<<8);	/* ECC: None */  
  1849 	csd|=		(0x0<<1);	/* CRC: ? */  
  1850 	csd|=		(0x1);		/* not used */  
  1851 	TMMC::BigEndian4Bytes(&aResp[12],csd);
  1852 	}
  1853 
  1854 // ======== DWinsSDIOPsu ========
  1855 
  1856 
  1857 DWinsSDIOPsu::DWinsSDIOPsu(TInt aVccNum, TInt aMcId)
  1858 	: DSDIOPsu(aVccNum, aMcId)
  1859 	{}
  1860 
  1861 void DWinsSDIOPsu::Init()
  1862 //
  1863 // Initialise the PSU
  1864 //
  1865     {
  1866 	// Nothing to do
  1867     }
  1868 
  1869 void DWinsSDIOPsu::DoSetState(TPBusPsuState aState)
  1870 //
  1871 // Turn on/off the PSU. If it is possible to adjust the output voltage on this
  1872 // PSU then retreive the required voltage level from TMMCPsu::iVoltageSetting
  1873 // (which is in OCR register format).
  1874 //
  1875     {
  1876 
  1877     switch (aState)
  1878         {
  1879         case EPsuOff:
  1880             break;
  1881         case EPsuOnFull:
  1882             break;
  1883         case EPsuOnCurLimit:
  1884             break;
  1885         }
  1886     }
  1887 
  1888 TInt DWinsSDIOPsu::VoltageInMilliVolts()
  1889 //
  1890 // Return the level of the PSU (in mV) or -ve if error.
  1891 //
  1892     {
  1893 
  1894     return(0);
  1895     }
  1896 
  1897 void DWinsSDIOPsu::DoCheckVoltage()
  1898 //
  1899 // Check the voltage level of the PSU is as expected. Returns either KErrNone, KErrGeneral 
  1900 // to indicate the pass/fail state or KErrNotReady if the voltage check isn't complete.
  1901 //
  1902     {
  1903 
  1904 	ReceiveVoltageCheckResult(KErrNone);
  1905     }
  1906 
  1907 void DWinsSDIOPsu::PsuInfo(TPBusPsuInfo &anInfo)
  1908 //
  1909 // Return machine info relating to the MMC PSU supply
  1910 //
  1911     {
  1912 
  1913 	anInfo.iVoltageSupported=0x00040000; // 3.0V (OCR reg. format).
  1914 	anInfo.iMaxCurrentInMicroAmps=0;
  1915 	anInfo.iVoltCheckInterval=0;
  1916 	anInfo.iVoltCheckMethod=EPsuChkComparator;
  1917 
  1918 	anInfo.iNotLockedTimeOut=5;
  1919 	anInfo.iInactivityTimeOut=10;
  1920     }