1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/boardsupport/emulator/emulatorbsp/specific/sdcard/sdcard3c/sdio/pp_sdio.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1920 @@
1.4 +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "plat_priv.h"
1.20 +#include <property.h>
1.21 +#include <variant.h>
1.22 +#include "pp_sdio.h"
1.23 +
1.24 +const TInt KDiskSectorSize=512;
1.25 +
1.26 +const TInt KTotalMDiskSize=0x100000; // 1MB (if changing this then also change CSD response)
1.27 +
1.28 +// ======== Register Map ========
1.29 +
1.30 +typedef TInt (*TAccessFunction)(TInt aTargetCard, TInt aVal, TAny* aThis, TBool aRead, TUint8& aData);
1.31 +
1.32 +const TInt KIoMapEnd = 0xFFFFFFFF;
1.33 +
1.34 +struct SRegisterMapInfo
1.35 + {
1.36 +public:
1.37 + TUint32 iRegisterID; // Unique ID
1.38 +
1.39 + const SRegisterMapInfo* iChildMapP; // Pointer to child register map
1.40 +
1.41 + TUint32 iAddress; // Start Address
1.42 + TUint32 iLength; // Register Length in Bytes
1.43 +
1.44 + const TAny* iDataP; // Data for auto-access (may be NULL)
1.45 + TAccessFunction iAccessFunction; // Invoked when register is accessed
1.46 +
1.47 + TUint8 iFlags; // Bitmap of RO(0), R/W(1) bits (8-bit only?)
1.48 + };
1.49 +
1.50 +// ======== Card Information Structures =========
1.51 +
1.52 +
1.53 +
1.54 +const TUint32 KCommonCisPtr = 0x1010;
1.55 +const TUint32 KCommonCisLen = 0x70;
1.56 +
1.57 +LOCAL_D const TText8 CardCommonCis[KCommonCisLen] =
1.58 + {
1.59 +// 0x20,0x04,0xc0,0x12,0x00,0x00,0x21,0x02,0x0c,0x00,0x22,0x06,0x00,0x00,0x01,0x32,
1.60 +// 0x00,0x00,0x91,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x32,0x01,0x00,0x48,0x41,
1.61 +// 0x47,0x49,0x57,0x41,0x52,0x41,0x20,0x53,0x59,0x53,0x2d,0x43,0x4f,0x4d,0x20,0x43,
1.62 +// 0x4f,0x2e,0x2c,0x4c,0x54,0x44,0x2e,0x00,0x48,0x53,0x2d,0x53,0x44,0x44,0x4b,0x2d,
1.63 +// 0x30,0x30,0x32,0x20,0x56,0x65,0x72,0x2e,0x50,0x61,0x6e,0x61,0x00,0x00,0xff,0xff,
1.64 +// 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1.65 +// 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
1.66 +
1.67 + 0x20,0x04,0xc0,0x12,0x00,0x00,0x21,0x02,0x0c,0x00,0x22,0x04,0x00,0x00,0x01,0x2A/*79*/,
1.68 + 0x91,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x35,0x01,0x00,0x48,0x41,0x47,0x49,
1.69 + 0x57,0x41,0x52,0x41,0x20,0x53,0x59,0x53,0x2d,0x43,0x4f,0x4d,0x20,0x43,0x4f,0x2e,
1.70 + 0x2c,0x4c,0x54,0x44,0x2e,0x00,0x48,0x53,0x2d,0x53,0x44,0x44,0x4b,0x2d,0x30,0x30,
1.71 + 0x32,0x20,0x56,0x65,0x72,0x2e,0x50,0x61,0x6e,0x61,0x00,0x53,0x48,0x50,0x00,0xff,
1.72 + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1.73 + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
1.74 + };
1.75 +
1.76 +const TUint32 KFn1CisPtr = 0x2000;
1.77 +const TUint32 KFn1CisLen = 0x40;
1.78 +
1.79 +LOCAL_D const TText8 Fn1Cis[KFn1CisLen] =
1.80 + {
1.81 + 0x21,0x02,0x0c,0x00,0x22,0x24,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
1.82 + 0x00,0x03,0x00,0x02,0x00,0x00,0x3c,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,
1.83 + 0x00,0x00,0x00,0x00,0x2c,0x01,0xf4,0x01,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
1.84 + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,
1.85 + };
1.86 +
1.87 +const TUint32 KFn2CisPtr = 0x3000;
1.88 +const TUint32 KFn2CisLen = 0x40;
1.89 +
1.90 +LOCAL_D const TText8 Fn2Cis[KFn2CisLen] =
1.91 + {
1.92 + 0x21,0x02,0x0c,0x00,0x22,0x24,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
1.93 + 0x00,0x03,0x40,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,
1.94 + 0x00,0x00,0x00,0x00,0xfa,0x00,0xc2,0x01,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
1.95 + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1.96 + };
1.97 +
1.98 +
1.99 +// ======== Card Common Control Registers =========
1.100 +
1.101 +TUint8 GCCCRRegSdioRevision = 0x00;
1.102 +TUint8 GCCCRRegSdSpec = 0x00;
1.103 +TUint8 GCCCRRegIoEnable = 0x00;
1.104 +TUint8 GCCCRRegIoReady = 0x00;
1.105 +TUint8 GCCCRRegIntEnable = 0x00;
1.106 +TUint8 GCCCRRegIntPending = 0x00;
1.107 +TUint8 GCCCRRegIoAbort = 0x00;
1.108 +TUint8 GCCCRRegBusInterfaceControl = 0x00;
1.109 +TUint8 GCCCRRegCardCapability = 0x00;
1.110 +TUint8 GCCCRRegCisPtrLo = (KCommonCisPtr & 0x0000FF);
1.111 +TUint8 GCCCRRegCisPtrMid = (KCommonCisPtr & 0x00FF00) >> 8;
1.112 +TUint8 GCCCRRegCisPtrHi = (KCommonCisPtr & 0xFF0000) >> 16;
1.113 +TUint8 GCCCRRegBusSuspend = 0x00;
1.114 +TUint8 GCCCRRegFunctionSelect = 0x00;
1.115 +TUint8 GCCCRRegExecFlags = 0x00;
1.116 +TUint8 GCCCRRegReadyFlags = 0x00;
1.117 +TUint8 GCCCRRegFN0BlockSizeLo = 0x00; // Initialises with 0x0000
1.118 +TUint8 GCCCRRegFN0BlockSizeHi = 0x00; // Initialises with 0x0000
1.119 +
1.120 +TUint8 GFunctionToEnable = 0x00;
1.121 +
1.122 +LOCAL_D const SRegisterMapInfo IoMapCCCR[] =
1.123 + {
1.124 + {KCCCRRegSdioRevision, NULL, 0x00, 0x01, &GCCCRRegSdioRevision, NULL, 0x00},
1.125 + {KCCCRRegSdSpec, NULL, 0x01, 0x01, &GCCCRRegSdSpec, NULL, 0x00},
1.126 +
1.127 + {KCCCRRegIoEnable, NULL, 0x02, 0x01, NULL, DWinsSDIOStack::AccessIoEnable, 0x00},
1.128 +
1.129 + {KCCCRRegIoReady, NULL, 0x03, 0x01, &GCCCRRegIoReady, NULL, 0x00},
1.130 + {KCCCRRegIntEnable, NULL, 0x04, 0x01, &GCCCRRegIntEnable, NULL, 0xFF},
1.131 + {KCCCRRegIntPending, NULL, 0x05, 0x01, &GCCCRRegIntPending, NULL, 0x00},
1.132 + {KCCCRRegIoAbort, NULL, 0x06, 0x01, &GCCCRRegIoAbort, NULL, 0xFF},
1.133 + {KCCCRRegBusInterfaceControl, NULL, 0x07, 0x01, &GCCCRRegBusInterfaceControl, NULL, 0xFF},
1.134 + {KCCCRRegCardCapability, NULL, 0x08, 0x01, &GCCCRRegCardCapability, NULL, 0x00},
1.135 + {KCCCRRegCisPtrLo, NULL, 0x09, 0x01, &GCCCRRegCisPtrLo, NULL, 0x00},
1.136 + {KCCCRRegCisPtrMid, NULL, 0x0a, 0x01, &GCCCRRegCisPtrMid, NULL, 0x00},
1.137 + {KCCCRRegCisPtrHi, NULL, 0x0b, 0x01, &GCCCRRegCisPtrHi, NULL, 0x00},
1.138 + {KCCCRRegBusSuspend, NULL, 0x0c, 0x01, &GCCCRRegBusSuspend, NULL, 0xFF},
1.139 + {KCCCRRegFunctionSelect, NULL, 0x0d, 0x01, &GCCCRRegFunctionSelect, NULL, 0xFF},
1.140 + {KCCCRRegExecFlags, NULL, 0x0e, 0x01, &GCCCRRegExecFlags, NULL, 0x00},
1.141 + {KCCCRRegReadyFlags, NULL, 0x0f, 0x01, &GCCCRRegReadyFlags, NULL, 0x00},
1.142 + {KCCCRRegFN0BlockSizeLo, NULL, 0x10, 0x01, &GCCCRRegFN0BlockSizeLo, NULL, 0x00},
1.143 + {KCCCRRegFN0BlockSizeHi, NULL, 0x11, 0x01, &GCCCRRegFN0BlockSizeHi, NULL, 0x00},
1.144 + {KIoMapEnd, NULL, 0, 0, NULL, NULL, 0xFF}
1.145 + };
1.146 +
1.147 +
1.148 +// ======== Function Basic Register 1 =========
1.149 +
1.150 +TUint8 GFBR1RegInterfaceCode = KFBRRegSupportsCSA;
1.151 +TUint8 GFBR1RegExtendedCode = 0x00;
1.152 +TUint8 GFBR1RegPowerFlags = 0x00;
1.153 +TUint8 GFBR1RegCisPtrLo = (KFn1CisPtr & 0x0000FF);
1.154 +TUint8 GFBR1RegCisPtrMid = (KFn1CisPtr & 0x00FF00) >> 8;
1.155 +TUint8 GFBR1RegCisPtrHi = (KFn1CisPtr & 0xFF0000) >> 16;
1.156 +TUint8 GFBR1RegIoBlockSizeLo = 0x00;
1.157 +TUint8 GFBR1RegIoBlockSizeHi = 0x00;
1.158 +
1.159 +TUint32 GFBR1RegCsaPtr = 0x00000000;
1.160 +
1.161 +LOCAL_D const SRegisterMapInfo IoMapFBR1[] =
1.162 + {
1.163 + {KFBRRegInterfaceCode, NULL, 0x100, 0x01, &GFBR1RegInterfaceCode, NULL, 0x00},
1.164 + {KFBRRegExtendedCode, NULL, 0x101, 0x01, &GFBR1RegExtendedCode, NULL, 0x00},
1.165 + {KFBRRegPowerFlags, NULL, 0x102, 0x01, &GFBR1RegPowerFlags, NULL, 0x00},
1.166 + {KFBRRegCisPtrLo, NULL, 0x109, 0x01, &GFBR1RegCisPtrLo, NULL, 0x00},
1.167 + {KFBRRegCisPtrMid, NULL, 0x10a, 0x01, &GFBR1RegCisPtrMid, NULL, 0x00},
1.168 + {KFBRRegCisPtrHi, NULL, 0x10b, 0x01, &GFBR1RegCisPtrHi, NULL, 0x00},
1.169 +
1.170 + {KFBRRegCsaPtrLo, NULL, 0x10c, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
1.171 + {KFBRRegCsaPtrMid, NULL, 0x10d, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
1.172 + {KFBRRegCsaPtrHi, NULL, 0x10e, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
1.173 + {KFBRRegCsaWindow, NULL, 0x10f, 0x01, NULL, DWinsSDIOStack::AccessCsaWindow, 0xFF},
1.174 +
1.175 + {KFBRRegIoBlockSizeLo, NULL, 0x110, 0x01, &GFBR1RegIoBlockSizeLo, NULL, 0xFF},
1.176 + {KFBRRegIoBlockSizeHi, NULL, 0x111, 0x01, &GFBR1RegIoBlockSizeHi, NULL, 0xFF},
1.177 + {KIoMapEnd, NULL, 0, 0, NULL, NULL, 0x00}
1.178 + };
1.179 +
1.180 +// ======== Function Basic Register 2 ========
1.181 +
1.182 +TUint8 GFBR2RegInterfaceCode = KFBRRegSupportsCSA | ESdioFunctionTypeUART;
1.183 +TUint8 GFBR2RegExtendedCode = 0x00;
1.184 +TUint8 GFBR2RegPowerFlags = 0x00;
1.185 +TUint8 GFBR2RegCisPtrLo = (KFn2CisPtr & 0x0000FF);
1.186 +TUint8 GFBR2RegCisPtrMid = (KFn2CisPtr & 0x00FF00) >> 8;
1.187 +TUint8 GFBR2RegCisPtrHi = (KFn2CisPtr & 0xFF0000) >> 16;
1.188 +TUint8 GFBR2RegIoBlockSizeLo = 0x00;
1.189 +TUint8 GFBR2RegIoBlockSizeHi = 0x00;
1.190 +
1.191 +TUint32 GFBR2RegCsaPtr = 0x00000000;
1.192 +
1.193 +LOCAL_D const SRegisterMapInfo IoMapFBR2[] =
1.194 + {
1.195 + {KFBRRegInterfaceCode, NULL, 0x200, 0x01, &GFBR2RegInterfaceCode, NULL, 0x00},
1.196 + {KFBRRegExtendedCode, NULL, 0x201, 0x01, &GFBR2RegExtendedCode, NULL, 0x00},
1.197 + {KFBRRegPowerFlags, NULL, 0x202, 0x01, &GFBR2RegPowerFlags, NULL, 0x00},
1.198 + {KFBRRegCisPtrLo, NULL, 0x209, 0x01, &GFBR2RegCisPtrLo, NULL, 0x00},
1.199 + {KFBRRegCisPtrMid, NULL, 0x20a, 0x01, &GFBR2RegCisPtrMid, NULL, 0x00},
1.200 + {KFBRRegCisPtrHi, NULL, 0x20b, 0x01, &GFBR2RegCisPtrHi, NULL, 0x00},
1.201 +
1.202 + {KFBRRegCsaPtrLo, NULL, 0x20c, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
1.203 + {KFBRRegCsaPtrMid, NULL, 0x20d, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
1.204 + {KFBRRegCsaPtrHi, NULL, 0x20e, 0x01, NULL, DWinsSDIOStack::AccessCsaPointer, 0xFF},
1.205 + {KFBRRegCsaWindow, NULL, 0x20f, 0x01, NULL, DWinsSDIOStack::AccessCsaWindow, 0xFF},
1.206 +
1.207 + {KFBRRegIoBlockSizeLo, NULL, 0x210, 0x01, &GFBR2RegIoBlockSizeLo, NULL, 0xFF},
1.208 + {KFBRRegIoBlockSizeHi, NULL, 0x211, 0x01, &GFBR2RegIoBlockSizeHi, NULL, 0xFF},
1.209 + {KIoMapEnd, NULL, 0, 0, NULL, NULL, 0x00}
1.210 + };
1.211 +
1.212 +// ======== Function Basic Register 1 =========
1.213 +
1.214 +const TInt KIoMapCCCR = 0;
1.215 +const TInt KIoMapFBR1 = 1;
1.216 +const TInt KIoMapFBR2 = 2;
1.217 +const TInt KIoMapCommonCis = 3;
1.218 +const TInt KIoMapFn1Cis = 4;
1.219 +const TInt KIoMapFn2Cis = 5;
1.220 +
1.221 +LOCAL_D const SRegisterMapInfo IoMapTop[] =
1.222 + {
1.223 + {KIoMapCCCR, IoMapCCCR, 0x00, 0xFF, NULL, NULL, 0x00},
1.224 + {KIoMapFBR1, IoMapFBR1, 0x100, 0xFF, NULL, NULL, 0x00},
1.225 + {KIoMapFBR2, IoMapFBR2, 0x200, 0xFF, NULL, NULL, 0x00},
1.226 + {KIoMapCommonCis, NULL, KCommonCisPtr, KCommonCisLen, CardCommonCis, NULL, 0x00},
1.227 + {KIoMapFn1Cis, NULL, KFn1CisPtr, KFn1CisLen, Fn1Cis, NULL, 0x00},
1.228 + {KIoMapFn2Cis, NULL, KFn2CisPtr, KFn2CisLen, Fn2Cis, NULL, 0x00},
1.229 + {KIoMapEnd, NULL, 0, 0, NULL, NULL, 0x00}
1.230 + };
1.231 +
1.232 +const SRegisterMapInfo* FindIoEntryFromID(const SRegisterMapInfo* aIoMapP, TUint32 aID)
1.233 + {
1.234 + const SRegisterMapInfo* foundEntry = NULL;
1.235 +
1.236 + TInt currentEntry = 0;
1.237 +
1.238 + while((aIoMapP[currentEntry].iRegisterID != KIoMapEnd) && (foundEntry == NULL))
1.239 + {
1.240 + if(aIoMapP[currentEntry].iRegisterID == aID)
1.241 + {
1.242 + foundEntry = aIoMapP+currentEntry;
1.243 + }
1.244 + currentEntry++;
1.245 + }
1.246 +
1.247 + return(foundEntry);
1.248 + }
1.249 +
1.250 +const SRegisterMapInfo* FindIoEntryFromAddress(const SRegisterMapInfo* aIoMapP, TUint32 aAddr)
1.251 + {
1.252 + const SRegisterMapInfo* foundEntry = NULL;
1.253 +
1.254 + TInt currentEntry = 0;
1.255 +
1.256 + while((aIoMapP[currentEntry].iRegisterID != KIoMapEnd) && (foundEntry == NULL))
1.257 + {
1.258 + const TUint32 startAddr = aIoMapP[currentEntry].iAddress;
1.259 + const TUint32 endAddr = startAddr + aIoMapP[currentEntry].iLength - 1;
1.260 +
1.261 + if((aAddr >= startAddr) && (aAddr <= endAddr))
1.262 + {
1.263 + if(aIoMapP[currentEntry].iChildMapP)
1.264 + {
1.265 + foundEntry = FindIoEntryFromAddress(aIoMapP[currentEntry].iChildMapP, aAddr);
1.266 + }
1.267 + else
1.268 + {
1.269 + foundEntry = aIoMapP+currentEntry;
1.270 + }
1.271 + }
1.272 + currentEntry++;
1.273 + }
1.274 +
1.275 + return(foundEntry);
1.276 + }
1.277 +
1.278 +
1.279 +
1.280 +// ======== error code conversion ========
1.281 +
1.282 +GLDEF_C TInt MapLastErrorEpoc()
1.283 +//
1.284 +// map an Win32 error code to Epoc32 value
1.285 +//
1.286 + {
1.287 + TInt res=KErrGeneral;
1.288 + switch (GetLastError())
1.289 + {
1.290 + case ERROR_SHARING_VIOLATION : res=KErrAccessDenied; break;
1.291 + case ERROR_LOCK_VIOLATION : res=KErrLocked; break;
1.292 + case ERROR_FILE_NOT_FOUND: res=KErrNotFound; break;
1.293 + case ERROR_PATH_NOT_FOUND: res=KErrPathNotFound; break;
1.294 + case ERROR_ALREADY_EXISTS:
1.295 + case ERROR_FILE_EXISTS:
1.296 + res=KErrAlreadyExists;
1.297 + break;
1.298 + case ERROR_NOT_READY: res=KErrNotReady; break;
1.299 + case ERROR_UNRECOGNIZED_VOLUME:
1.300 + case ERROR_NOT_DOS_DISK:
1.301 + res=KErrUnknown;
1.302 + break;
1.303 + case ERROR_UNRECOGNIZED_MEDIA: res=KErrCorrupt; break;
1.304 + case ERROR_INVALID_NAME: res=KErrBadName; break;
1.305 + case ERROR_NO_MORE_FILES: res=KErrEof; break;
1.306 + }
1.307 + return(res);
1.308 + }
1.309 +
1.310 +GLDEF_C TMMCErr MapLastErrorMmc()
1.311 +//
1.312 +// map Win32 error to a TMMCErr error.
1.313 +//
1.314 + {
1.315 + DWORD r=GetLastError();
1.316 + TInt res=KErrGeneral;
1.317 + switch (r)
1.318 + {
1.319 + case ERROR_SHARING_VIOLATION:
1.320 + case ERROR_LOCK_VIOLATION:
1.321 + res=KMMCErrLocked; // KErrLocked
1.322 + break;
1.323 + case ERROR_FILE_NOT_FOUND:
1.324 + case ERROR_PATH_NOT_FOUND:
1.325 + res=KMMCErrNotFound; // KErrNotFound
1.326 + break;
1.327 + case ERROR_ALREADY_EXISTS:
1.328 + case ERROR_FILE_EXISTS:
1.329 + res=KMMCErrAlreadyExists; // KErrAlreadyExists
1.330 + break;
1.331 + case ERROR_NOT_READY: res=KMMCErrNoCard; break;
1.332 + case ERROR_UNRECOGNIZED_VOLUME:
1.333 + case ERROR_NOT_DOS_DISK:
1.334 + res=KMMCErrGeneral; // KErrGeneral
1.335 + break;
1.336 + case ERROR_UNRECOGNIZED_MEDIA:
1.337 + case ERROR_INVALID_NAME:
1.338 + case ERROR_NO_MORE_FILES:
1.339 + res=KMMCErrResponseCRC; // KErrCorrupt
1.340 + break;
1.341 + }
1.342 + return(res);
1.343 + }
1.344 +
1.345 +// ======== DWinsSDIOStack ========
1.346 +
1.347 +DWinsSDIOStack::DWinsSDIOStack(TInt aBus, DMMCSocket* aSocket)
1.348 + : DSDIOStack(aBus, aSocket),
1.349 + iEnableTimer(&DWinsSDIOStack::EnableTimerCallback,this)
1.350 + {
1.351 + iAddressedCard=KBroadcastToAllCards;
1.352 +// iCMD42Failed=EFalse;
1.353 + }
1.354 +
1.355 +
1.356 +TInt DWinsSDIOStack::Init()
1.357 +//
1.358 +// Allocate any resources. Only created once on kernel initialization so dont
1.359 +// worry about cleanup if it leaves.
1.360 +//
1.361 + {
1.362 + if((iCardArray = new TSDIOCardArray(this)) == NULL)
1.363 + return KErrNoMemory;
1.364 +
1.365 + TInt r=DMMCStack::Init();
1.366 + if(r!=KErrNone)
1.367 + return r;
1.368 +
1.369 + DMediaChangeBase* pMCBase = MMCSocket()->iMediaChange;
1.370 + static_cast<DWinsMMCMediaChange*>(pMCBase)->SetStackP(this);
1.371 + Wins::SetMediaChangeCallBackPtr(DWinsMMCMediaChange::MediaChangeCallBack, (TAny*)pMCBase);
1.372 +
1.373 + //
1.374 + // Over time memory can become fragmented, and so it is not possible to
1.375 + // allocate physically contiguous pages. Therefore, the buffers for IO
1.376 + // are allocated at startup.
1.377 + //
1.378 + // block and erase sector size characteristics depend on the specific
1.379 + // card model, and so the initial values are estimates based on a typical
1.380 + // card. If these do not match the actual card's block size (or erase
1.381 + // size, for SD,) then the media driver just gets a reduced or increased
1.382 + // buffer area, and its efficiency varies accordingly.
1.383 + //
1.384 + // For the WINS implementation, fragmentation does not matter because
1.385 + // DMA is not used. The memory must still be allocated here so MEDMMC is
1.386 + // able to use it.
1.387 + //
1.388 + // The constant calculations could be folded, but this illustrates how the
1.389 + // values are derived.
1.390 + //
1.391 +
1.392 + // MMC - values from Hitachi 16Mb card, datasheet HB288016MM1
1.393 +
1.394 + // minor buffer must contain enough space for MBR or block
1.395 + const TUint mmcBlkSzLog2 = 9; // READ_BLK_LEN and WRITE_BLK_LEN
1.396 + const TUint mmcBlkSz = 1 << mmcBlkSzLog2;
1.397 + const TInt mmcMinorBufLen = Max(KDiskSectorSize, mmcBlkSz);
1.398 +
1.399 + const TInt KMinMMCBlocksInBuffer = 8;
1.400 + const TInt mmcCchBufLen = KMinMMCBlocksInBuffer << mmcBlkSzLog2;
1.401 +
1.402 + const TInt mmcTotalBufLen = mmcMinorBufLen + mmcCchBufLen;
1.403 +
1.404 + // SDCard - values from 64Mb Panasonic RP-SD064
1.405 +
1.406 + const TUint sdBlkSzLog2 = 9; // READ_BL_LEN and WRITE_BLK_LEN
1.407 + const TUint sdBlkSz = 1 << sdBlkSzLog2;
1.408 + const TInt sdMinorBufLen = Max(KDiskSectorSize, sdBlkSz);
1.409 +
1.410 + const TUint ss = 0x1f; // SECTOR_SIZE, add 1 for sector count
1.411 + const TInt KMinSDBlocksInBuffer = 8;
1.412 + const TInt sdCchBufLen = Max(KMinSDBlocksInBuffer, ss + 1) << sdBlkSzLog2;
1.413 +
1.414 + const TInt sdTotalBufLen = sdMinorBufLen + sdCchBufLen;
1.415 +
1.416 + const TInt totalBufLen = Max(mmcTotalBufLen, sdTotalBufLen);
1.417 +
1.418 + iMDBuf = reinterpret_cast<TUint8*>(Kern::Alloc(totalBufLen));
1.419 + iMDBufLen = totalBufLen;
1.420 +
1.421 + // initialize each card on the stack
1.422 + TInt i;
1.423 + for (i = 0; i < KTotalWinsCards; ++i)
1.424 + {
1.425 + TInt r = SetupSimulatedCard(i);
1.426 + if (r != KErrNone)
1.427 + return r;
1.428 + }
1.429 +
1.430 + // initialize pointers to currently present cards
1.431 +
1.432 + // Slot zero can toggle between no card; card 0 and card 1. The current state is
1.433 + // determined by *Wins::CurrentPBusDevicePtr() and toggled by pressing F4 when F5
1.434 + // (door open) is held down. Because this function is only executed at startup,
1.435 + // assume start with card zero.
1.436 + iCardInfo[0] = iCardPool[0];
1.437 + for (i = 1; i < KTotalWinsCardSlots; ++i)
1.438 + {
1.439 + iCardInfo[i]=iCardPool[i+1];
1.440 + }
1.441 +
1.442 + return KErrNone;
1.443 + }
1.444 +
1.445 +void DWinsSDIOStack::MachineInfo(TMMCMachineInfo& aMachineInfo)
1.446 + {
1.447 + aMachineInfo.iTotalSockets=KTotalWinsCardSlots;
1.448 + aMachineInfo.iTotalMediaChanges=0; // Not used at present
1.449 + aMachineInfo.iTotalPrimarySupplies=0; // Not used at present
1.450 +
1.451 + aMachineInfo.iSPIMode=EFalse;
1.452 + aMachineInfo.iBaseBusNumber=0;
1.453 +
1.454 + __ASSERT_DEBUG(aMachineInfo.iTotalSockets<=KMaxMMCardsPerStack,
1.455 + DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCBadMachineInfo));
1.456 + }
1.457 +
1.458 +void DWinsSDIOStack::AdjustPartialRead(
1.459 +#ifdef _DEBUG
1.460 + const TMMCard* aCard,
1.461 +#else
1.462 + const TMMCard* /*aCard*/,
1.463 +#endif
1.464 + TUint32 aStart, TUint32 aEnd, TUint32* aPhysStart, TUint32* aPhysEnd) const
1.465 + {
1.466 +#ifdef _DEBUG
1.467 + const TUint32 blkLen = aCard->CSD().ReadBlockLength();
1.468 + const TUint32 blkMsk = blkLen - 1;
1.469 +
1.470 + __ASSERT_DEBUG(aCard->CSD().ReadBlPartial(), Panic(EWinsMMCAPRNotSupp));
1.471 + __ASSERT_DEBUG(aEnd - aStart <= blkLen, Panic(EWinsMMCAPRRange));
1.472 + __ASSERT_DEBUG((aEnd & ~blkMsk) > (aStart & ~blkMsk), Panic(EWinsMMCAPRBoundary));
1.473 +#endif
1.474 +
1.475 + *aPhysStart = aStart & ~0x3;
1.476 + *aPhysEnd = (aEnd + 0x3) & ~0x3;
1.477 + }
1.478 +
1.479 +void DWinsSDIOStack::GetBufferInfo(TUint8** aMDBuf, TInt* aMDBufLen)
1.480 + {
1.481 + *aMDBuf = iMDBuf;
1.482 + *aMDBufLen = iMDBufLen;
1.483 + }
1.484 +
1.485 +void DWinsSDIOStack::Panic(TWinsMMCPanic aPanic)
1.486 + {
1.487 + _LIT(KPncNm,"PBUS-MMCSD-WINS");
1.488 + Kern::PanicCurrentThread(KPncNm,aPanic);
1.489 + }
1.490 +
1.491 +TInt DWinsSDIOStack::SetupSimulatedCard(TInt aCardNum)
1.492 +//
1.493 +// allocate individual card with Win32 file. Only called at bootup, so no cleanup if fails.
1.494 +//
1.495 + {
1.496 + TWinsCardInfo* cip = new TWinsCardInfo;
1.497 + if (cip == 0)
1.498 + return KErrNoMemory;
1.499 +
1.500 + TUint8 cid[KMMCCIDLength];
1.501 + cid[0] = 'C';
1.502 + cid[1] = 'I';
1.503 + cid[2] = 'D';
1.504 + cid[3] = TUint8('0' + aCardNum);
1.505 + TInt j;
1.506 + for (j = 4; j < KMMCCIDLength - 1; ++j)
1.507 + cid[j] = 'c';
1.508 + cid[KMMCCIDLength - 1] = '#'; // '#' = 0x23, bit zero must be 1
1.509 + cip->iCID=cid;
1.510 +
1.511 + cip->iPWD = new TMediaPassword;
1.512 + if (! cip->iPWD)
1.513 + {
1.514 + delete cip;
1.515 + return KErrNoMemory;
1.516 + }
1.517 +
1.518 + // cards in slot zero are SD
1.519 + TInt mediaAreas;
1.520 + if (aCardNum <= 1)
1.521 + {
1.522 + cip->iIsSDCard = ETrue;
1.523 + mediaAreas = 3; // +1 for SDIO area
1.524 + }
1.525 + else
1.526 + {
1.527 + cip->iIsSDCard = EFalse;
1.528 + mediaAreas = 1;
1.529 + }
1.530 +
1.531 + cip->iState=ECardStateIdle;
1.532 +
1.533 + for (TInt area = 0; area < mediaAreas; ++area)
1.534 + {
1.535 + TInt r = CreateBinFileForCard(aCardNum, area, &cip->iAreaHandles[area]);
1.536 + if (r != KErrNone)
1.537 + return r;
1.538 + }
1.539 + iCardPool[aCardNum]=cip;
1.540 + return(KErrNone);
1.541 + }
1.542 +
1.543 +TInt DWinsSDIOStack::CreateBinFileForCard(TInt aCardNum, TInt aAreaNum, HANDLE* aHandle)
1.544 +//
1.545 +// create .bin file in temp directory to contain media area of card.
1.546 +//
1.547 + {
1.548 + const char* emulatorPath = Property::GetString("EmulatorMediaPath");
1.549 + if (!Emulator::CreateAllDirectories(emulatorPath))
1.550 + return Emulator::LastError();
1.551 +
1.552 + TBuf8<KMaxFileName> fn8(_L8(emulatorPath));
1.553 + fn8.Append(_L8("MMCCRD"));
1.554 + fn8.AppendNum(aCardNum);
1.555 + fn8.Append('A'+aAreaNum);
1.556 + fn8.Append(_L8(".BIN"));
1.557 + fn8.Append('\0');
1.558 +
1.559 + *aHandle = CreateFileA(
1.560 + (LPCSTR) fn8.Ptr(), // LPCSTR lpFileName,
1.561 + GENERIC_READ | GENERIC_WRITE, // DWORD dwDesiredAccess
1.562 + FILE_SHARE_READ | FILE_SHARE_WRITE, // DWORD dwShareMode
1.563 + NULL, // LPSECURITY_ATTRIBUTES lpSecurityAttributes
1.564 + OPEN_ALWAYS, // DWORD dwCreationDisposition
1.565 + FILE_FLAG_RANDOM_ACCESS, // DWORD dwFlagsAndAttributes
1.566 + NULL); // HANDLE hTemplateFile
1.567 +
1.568 + if (*aHandle == INVALID_HANDLE_VALUE)
1.569 + return MapLastErrorEpoc();
1.570 +
1.571 + if ( SetFilePointer(*aHandle, KTotalMDiskSize, NULL, FILE_BEGIN) == 0xffffffffu
1.572 + || ! SetEndOfFile(*aHandle) )
1.573 + {
1.574 + CloseHandle(*aHandle);
1.575 + return MapLastErrorEpoc();
1.576 + }
1.577 +
1.578 + return KErrNone;
1.579 + }
1.580 +
1.581 +void DWinsSDIOStack::SetBusConfigDefaults(TMMCBusConfig& aConfig, TUint aClock)
1.582 + {
1.583 + const TUint KWinsMaxHwInterfaceClk=104000;
1.584 + const TUint KWinsResponseTimeOut=6400;
1.585 + const TUint KWinsDataTimeOut=40000;
1.586 + const TUint KWinsBusyTimeOut=200000;
1.587 +
1.588 + aConfig.iBusClock = (aClock > KWinsMaxHwInterfaceClk) ? KWinsMaxHwInterfaceClk : aClock;
1.589 + aConfig.iResponseTimeOut=KWinsResponseTimeOut;
1.590 + aConfig.iDataTimeOut=KWinsDataTimeOut;
1.591 + aConfig.iBusyTimeOut=KWinsBusyTimeOut;
1.592 + }
1.593 +
1.594 +void DWinsSDIOStack::InitClockOff()
1.595 + {
1.596 + // empty.
1.597 + }
1.598 +
1.599 +void DWinsSDIOStack::ASSPReset()
1.600 + {
1.601 + // empty.
1.602 + }
1.603 +
1.604 +void DWinsSDIOStack::ASSPDisengage()
1.605 + {
1.606 + // empty.
1.607 + }
1.608 +
1.609 +void DWinsSDIOStack::DoPowerDown()
1.610 + {
1.611 + // empty.
1.612 + }
1.613 +
1.614 +
1.615 +LOCAL_C TInt SetMediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,const TDesC8& aPasswd)
1.616 +//
1.617 +// Set the password for local drive 'aLocalDrive', card number 'aCardNum' to 'aPasswd' - as an
1.618 +// environment variable. Note that the card number is only relevant where the emulated drive
1.619 +// supports card hot-swapping (i.e. F4 whilst F5 is held down).
1.620 +//
1.621 + {
1.622 + // Setup the appropriate environment variable string '_EPOC_LocDrv_<locDrvNum>_PWORD_<cardNum>'
1.623 + TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
1.624 +
1.625 + envVar[13]=(TUint16)('0'+aSocketNum);
1.626 + envVar[21]=(TUint16)('0'+aCardNum);
1.627 +
1.628 + // Setup the new value of the environment variable
1.629 + TUint16 envVal[100];
1.630 + TInt len=aPasswd.Length();
1.631 +
1.632 + // the password may be empty if a card's password is cleared
1.633 + if (len>(100-1))
1.634 + return(KErrArgument);
1.635 + memcpy(&envVal[0],reinterpret_cast<const TUint16 *>(aPasswd.Ptr()),len);
1.636 + envVal[len>>1]='\0';
1.637 +
1.638 + // Now set the new value for the environment variable
1.639 + if (SetEnvironmentVariable(envVar,&envVal[0]))
1.640 + return(KErrNone);
1.641 +
1.642 + return KErrGeneral;
1.643 + }
1.644 +
1.645 +LOCAL_C TInt MediaPasswordEnvironmentVar(TInt aSocketNum,TInt aCardNum,TDes8& aPasswd)
1.646 +//
1.647 +// Get the password for local drive 'aLocalDrive', card number 'aCardNum' into 'aPasswd' - from
1.648 +// an environment variable. Note that the card number is only relevant where the emulated drive
1.649 +// supports card hot-swapping (i.e. F4 whilst F5 is held down).
1.650 +//
1.651 + {
1.652 + TUint16 envVar[]=L"_EPOC_Socket_X_PWORD_Y";
1.653 +
1.654 + envVar[13]=(TUint16)('0'+aSocketNum);
1.655 + envVar[21]=(TUint16)('0'+aCardNum);
1.656 +
1.657 + TUint16 envVal[100]; // To hold the value of the retreived environment variable
1.658 +
1.659 + DWORD len=GetEnvironmentVariable(envVar,&envVal[0],100);
1.660 + if (len>(TUint)100)
1.661 + return(KErrGeneral);
1.662 + if (len)
1.663 + {
1.664 + // Found the requested environment variable so there is a password for this local drive / card.
1.665 + if ((len<<1)<=KMaxMediaPassword)
1.666 + {
1.667 + aPasswd.FillZ(KMaxMediaPassword);
1.668 + aPasswd.Zero();
1.669 + aPasswd.Copy(reinterpret_cast<TUint8*>(&envVal[0]),len<<1);
1.670 + return(KErrNone);
1.671 + }
1.672 + else
1.673 + return(KErrGeneral);
1.674 + }
1.675 +
1.676 + return(KErrNotFound);
1.677 + }
1.678 +
1.679 +TMMCErr DWinsSDIOStack::DoPowerUpSM()
1.680 + {
1.681 + enum states
1.682 + {
1.683 + EStBegin=0,
1.684 + EStEnd
1.685 + };
1.686 +
1.687 + SMF_BEGIN
1.688 +
1.689 + if(MMCSocket()->iVcc->SetState(EPsuOnCurLimit) != KErrNone)
1.690 + return KMMCErrHardware;
1.691 +
1.692 + for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
1.693 + {
1.694 + // if card has a password, it will be locked on power up
1.695 + TInt cardNum = (i==0) ? *Wins::CurrentPBusDevicePtr() : i + 1;
1.696 + if ( cardNum >= 0
1.697 + && MediaPasswordEnvironmentVar(
1.698 + MMCSocket()->iSocketNumber, cardNum, *(iCardInfo[i]->iPWD))
1.699 + == KErrNone)
1.700 + {
1.701 + iCardInfo[i]->iIsLocked = (iCardInfo[i]->iPWD->Length() > 0);
1.702 + }
1.703 + else
1.704 + iCardInfo[i]->iIsLocked=EFalse;
1.705 +
1.706 + iCardInfo[i]->iState = ECardStateIdle;
1.707 + iCardInfo[i]->iRCA=0x0001; // Default RCA - spec 2.2, s4.2.1, 5.4
1.708 + }
1.709 +
1.710 + ReportPowerUp();
1.711 +
1.712 + SMF_END
1.713 + }
1.714 +
1.715 +TMMCErr DWinsSDIOStack::InitClockOnSM()
1.716 + {
1.717 + enum states
1.718 + {
1.719 + EStBegin=0,
1.720 + EStEnd
1.721 + };
1.722 + SMF_BEGIN
1.723 +
1.724 + SMF_END
1.725 + }
1.726 +
1.727 +void DWinsSDIOStack::AddressCard(TInt aCardNumber)
1.728 + {
1.729 + iAddressedCard = aCardNumber;
1.730 + }
1.731 +
1.732 +
1.733 +TInt DWinsSDIOStack::GetTargetSlotNumber(const TRCA& anRCA)
1.734 +//
1.735 +// when the controller is given a command with an embedded RCA, this function
1.736 +// works out which physical card slot it corresponds to. If no card has been
1.737 +// assigned the RCA then it returns -1.
1.738 +//
1.739 + {
1.740 + TInt targetIdx = -1;
1.741 +
1.742 + for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
1.743 + {
1.744 + if (iCardInfo[i]->iRCA==anRCA)
1.745 + {
1.746 + targetIdx=i;
1.747 + break;
1.748 + }
1.749 + }
1.750 +
1.751 + return(targetIdx);
1.752 + }
1.753 +
1.754 +TMMCErr DWinsSDIOStack::IssueMMCCommandSM()
1.755 + {
1.756 + enum states
1.757 + {
1.758 + EStBegin=0,
1.759 + EStEnd
1.760 + };
1.761 +
1.762 + TMMCCommandDesc& cmd = Command();
1.763 +
1.764 + // If the command contains an embedded RCA then extract it
1.765 + TRCA tgtRCA=0;
1.766 + TBool supRCA=EFalse;
1.767 + if (/*cmd.iCommand == ECmdSetRelativeAddr || */cmd.iCommand == ECmdSelectCard
1.768 + || cmd.iCommand == ECmdSendCSD || cmd.iCommand == ECmdSendCID
1.769 + || cmd.iCommand == ECmdSendStatus || cmd.iCommand == ECmdGoInactiveState
1.770 + || cmd.iCommand == ECmdFastIO || cmd.iCommand == ECmdAppCmd )
1.771 + {
1.772 + if ((cmd.iArgument >> 16) != 0)
1.773 + {
1.774 + supRCA=ETrue;
1.775 + tgtRCA=TUint16(cmd.iArgument >> 16);
1.776 + }
1.777 + }
1.778 +
1.779 + // if the card contains an embedded RCA, work out which slot it corresponds to.
1.780 + // At the end of the function, this card is used to generate the R1 response.
1.781 + // Assume that if rca is supplied it either corresponds to the selected card or
1.782 + // broadcast mode is on. (An exception is CMD7 with arg0 to deselect all cards.)
1.783 +
1.784 + TInt targetCard = supRCA ? GetTargetSlotNumber(tgtRCA) : iAddressedCard;
1.785 + TBool rto = EFalse; // response timeout
1.786 +
1.787 + // if try to access card zero has been set to holding no card via F5 / F4 then timeout.
1.788 + if ((targetCard == 0) && *Wins::CurrentPBusDevicePtr() < 0)
1.789 + return KMMCErrResponseTimeOut;
1.790 +
1.791 + HANDLE winHandle;
1.792 +
1.793 + // CMD42 is a data transfer command. That means the R1 response that it returns
1.794 + // immediately is the state it is in on receiving the data block, and not after
1.795 + // processing it. If the data block is invalid then LOCK_UNLOCK_FAILED will be
1.796 + // set in the R1 response which is sent in reply to the next command.
1.797 +
1.798 + TBool nextCMD42Failed = EFalse;
1.799 + TBool lock_unlock_failed=EFalse;
1.800 +
1.801 + // When the card is locked, it will only respond to basic command class (0) and
1.802 + // lock card command class (7). An exception is CMD16. This is sent before CMD42,
1.803 + // but is classified (MMC Spec 23.2, table 5) as belonging to classes 2 and 4.
1.804 + // For data transfer commands, LOCK_UNLOCK_FAIL is set in response to the following
1.805 +
1.806 + TMMCCommandEnum origCmd = cmd.iCommand;
1.807 +
1.808 + // if targetting locked card...
1.809 + if (targetCard != KBroadcastToAllCards && iCardInfo[targetCard]->iIsLocked)
1.810 + {
1.811 + // ...and not command used in init or CMD42 sequence...
1.812 + if (!( ((cmd.iSpec.iCommandClass & (KMMCCmdClassApplication | KMMCCmdClassBasic | KMMCCmdClassLockCard)) != 0)
1.813 + || (cmd.iCommand == ECmdSetBlockLen) || (cmd.iCommand == ECmdAppCmd) ))
1.814 + {
1.815 + lock_unlock_failed = ETrue;
1.816 + cmd.iCommand = (TMMCCommandEnum) -1; // skip case processing
1.817 + }
1.818 + }
1.819 +
1.820 + SMF_BEGIN
1.821 +
1.822 + switch (cmd.iCommand)
1.823 + {
1.824 + case ECmdGoIdleState: // CMD0
1.825 + if (iAddressedCard != KBroadcastToAllCards)
1.826 + iCardInfo[iAddressedCard]->iState = ECardStateIdle;
1.827 + else
1.828 + {
1.829 + for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
1.830 + iCardInfo[i]->iState = ECardStateIdle;
1.831 + }
1.832 + break;
1.833 +
1.834 + case ECmd41:
1.835 + case ECmdSendOpCond: // CMD1
1.836 + {
1.837 + if (iAddressedCard != KBroadcastToAllCards)
1.838 + iCardInfo[iAddressedCard]->iState = ECardStateReady;
1.839 + else
1.840 + {
1.841 + for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
1.842 + iCardInfo[i]->iState = ECardStateReady;
1.843 + }
1.844 +
1.845 + // bit31 is set to indicate cards are not still powering up
1.846 + TUint32 r3 = KMMCWinsCardOCRValue | KMMCOCRBusy;
1.847 + TMMC::BigEndian4Bytes(cmd.iResponse, r3);
1.848 + }
1.849 + break;
1.850 +
1.851 + case ECmdAllSendCID: // CMD2
1.852 + {
1.853 + TInt idx;
1.854 + if (iAddressedCard != KBroadcastToAllCards)
1.855 + {
1.856 + idx = iAddressedCard;
1.857 + __ASSERT_DEBUG(
1.858 + iCardInfo[iAddressedCard]->iState == ECardStateReady,
1.859 + DWinsSDIOStack::Panic(DWinsSDIOStack::EStkIMCBadStateCmd2));
1.860 + }
1.861 + else
1.862 + idx = FindAnyCardInStack(ECardStateReady);
1.863 +
1.864 + if (idx == -1)
1.865 + rto = ETrue;
1.866 + else
1.867 + {
1.868 + iCardInfo[idx]->iCID.Copy(cmd.iResponse);
1.869 + iCardInfo[idx]->iState = ECardStateIdent;
1.870 + }
1.871 + }
1.872 + break;
1.873 +
1.874 + case ECmdSetRelativeAddr: // CMD3
1.875 + {
1.876 + TInt idx;
1.877 + if (iAddressedCard != KBroadcastToAllCards)
1.878 + {
1.879 + __ASSERT_DEBUG(
1.880 + iCardInfo[iAddressedCard]->iState == ECardStateIdent,
1.881 + DWinsSDIOStack::Panic(DWinsSDIOStack::EStkIMCBadStateCmd3));
1.882 +
1.883 + if (iCardInfo[iAddressedCard]->iIsSDCard)
1.884 + {
1.885 + static TUint16 RCACounter = 0x1234;
1.886 + // SD Cards publish RCAs
1.887 + ++RCACounter;
1.888 + iCardInfo[iAddressedCard]->iRCA = RCACounter;
1.889 + iCardInfo[iAddressedCard]->iState = ECardStateStby;
1.890 + TUint32 r6 = TUint32(RCACounter) << 16;
1.891 + TMMC::BigEndian4Bytes(&cmd.iResponse[0],r6); // Ignore bits 47-40
1.892 + }
1.893 + else
1.894 + {
1.895 + iCardInfo[iAddressedCard]->iRCA = TUint16(cmd.iArgument >> 16);
1.896 + iCardInfo[iAddressedCard]->iState=ECardStateStby;
1.897 + }
1.898 + }
1.899 + else
1.900 + {
1.901 + // MultiMediaCards are assigned RCAs
1.902 + idx = FindOneCardInStack(ECardStateIdent);
1.903 + iCardInfo[iAddressedCard]->iRCA = TUint16(cmd.iArgument >> 16);
1.904 + iCardInfo[iAddressedCard]->iState=ECardStateStby;
1.905 + targetCard = iAddressedCard;
1.906 + }
1.907 + }
1.908 + break;
1.909 +
1.910 + case ECmd6:
1.911 + // if ACMD6 then change bus width
1.912 + if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
1.913 + {
1.914 + switch (cmd.iArgument)
1.915 + {
1.916 + case 0x00:
1.917 + iCardInfo[iAddressedCard]->iBusWidth = 1;
1.918 + break;
1.919 + case 0x02:
1.920 + iCardInfo[iAddressedCard]->iBusWidth = 4;
1.921 + break;
1.922 + default:
1.923 + DWinsSDIOStack::Panic(DWinsSDIOStack::EStkIMCCmd6InvalidWidth);
1.924 + break;
1.925 + }
1.926 + }
1.927 + break;
1.928 +
1.929 + case ECmdSelectCard: // CMD7
1.930 + {
1.931 + // switch to broadcast mode so the currently selected and new cards
1.932 + // receive the command simultaneously.
1.933 +
1.934 + TInt idx = FindAnyCardInStack(ECardStateTran);
1.935 + if (idx != -1)
1.936 + iCardInfo[idx]->iState = ECardStateStby;
1.937 + if ((iAddressedCard=targetCard) == KBroadcastToAllCards)
1.938 + rto = ETrue;
1.939 + else
1.940 + {
1.941 + iCardInfo[targetCard]->iState = ECardStateTran;
1.942 + targetCard = targetCard;
1.943 + }
1.944 + }
1.945 + break;
1.946 +
1.947 + case ECmdSendStatus:
1.948 + // R1 response so status return as for any other R1 command.
1.949 + if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
1.950 + {
1.951 + __ASSERT_DEBUG(
1.952 + iCardInfo[targetCard]->iIsSDCard,
1.953 + DWinsSDIOStack::Panic(DWinsSDIOStack::EStkICMACMD13NotSD));
1.954 +
1.955 + memset(cmd.iDataMemoryP, 0, KSDStatusBlockLength);
1.956 + if (iCardInfo[targetCard]->iBusWidth == 1)
1.957 + cmd.iDataMemoryP[0] = 0x00 << 6;
1.958 + else // if (iCardInfo[targetCard]->iBusWidth == 4)
1.959 + cmd.iDataMemoryP[0] = 0x02 << 6;
1.960 + cmd.iDataMemoryP[7] = 0x28; // PROTECTED_AREA_SIZE
1.961 + }
1.962 + break;
1.963 +
1.964 + case ECmdReadSingleBlock:
1.965 + case ECmdReadMultipleBlock:
1.966 + {
1.967 + winHandle=iCardInfo[targetCard]->iAreaHandles[KSDUserArea];
1.968 +
1.969 + if ( cmd.iSpec.iUseStopTransmission && cmd.iBlockLength >= cmd.iTotalLength)
1.970 + return( KMMCErrNotSupported );
1.971 +
1.972 + TMMCErr err;
1.973 + TInt pos = cmd.iArgument;
1.974 + if (SetFilePointer(winHandle,pos,NULL,FILE_BEGIN)==0xffffffffu)
1.975 + err=MapLastErrorMmc();
1.976 + else
1.977 + {
1.978 + DWORD res;
1.979 + TInt len = cmd.iTotalLength;
1.980 + if (ReadFile(winHandle,(TAny*)cmd.iDataMemoryP,len,&res,NULL)==FALSE)
1.981 + err=MapLastErrorMmc();
1.982 + else if (res!=(DWORD)len)
1.983 + err=KMMCErrGeneral;
1.984 + else
1.985 + err=KMMCErrNone;
1.986 + }
1.987 + if (err!=KMMCErrNone)
1.988 + return(err);
1.989 + break;
1.990 + }
1.991 +
1.992 + case ECmd22:
1.993 + if (cmd.iSpec.iCommandClass == KMMCCmdClassApplication)
1.994 + {
1.995 + TMMC::BigEndian4Bytes(cmd.iResponse, iMBWOKBlocks);
1.996 + }
1.997 + break;
1.998 + // ------------------------------------------------------------------
1.999 + case ECmdWriteBlock:
1.1000 + case ECmdWriteMultipleBlock:
1.1001 + {
1.1002 + TUint32 writeLen;
1.1003 +
1.1004 + // periodically fail multi-block writes to test ACMD22 error recovery
1.1005 + if (cmd.iCommand != ECmdWriteMultipleBlock)
1.1006 + writeLen = cmd.iTotalLength;
1.1007 + else
1.1008 + {
1.1009 + const TInt KMaxFailCnt = 4;
1.1010 + static TInt failCnt = 0;
1.1011 + const TInt KMaxFailBlock = 4;
1.1012 + static TInt failBlocks = 0;
1.1013 +
1.1014 + failCnt = (failCnt + 1) % KMaxFailCnt;
1.1015 + if (failCnt != 0)
1.1016 + writeLen = cmd.iTotalLength;
1.1017 + else
1.1018 + {
1.1019 + failBlocks = (failBlocks + 1) % KMaxFailBlock;
1.1020 +
1.1021 + // fail at least one block
1.1022 + TInt totalBlocks = cmd.iTotalLength / cmd.iBlockLength;
1.1023 + TInt blocksToFail = Min(failBlocks + 1, totalBlocks); // fail at least one block
1.1024 + iMBWOKBlocks = (totalBlocks - blocksToFail);
1.1025 + writeLen = iMBWOKBlocks * cmd.iBlockLength;
1.1026 + if (writeLen == 0)
1.1027 + return KMMCErrDataTimeOut;
1.1028 + }
1.1029 + }
1.1030 +
1.1031 + HANDLE h=iCardInfo[targetCard]->iAreaHandles[KSDUserArea];
1.1032 +
1.1033 + TMMCErr err;
1.1034 + TInt pos = cmd.iArgument;
1.1035 + if (SetFilePointer(h, pos, NULL, FILE_BEGIN)==0xffffffffu)
1.1036 + err = MapLastErrorMmc();
1.1037 + else
1.1038 + {
1.1039 + DWORD res;
1.1040 + if (! WriteFile(h, (LPCVOID)cmd.iDataMemoryP,writeLen,&res,NULL))
1.1041 + err=MapLastErrorMmc();
1.1042 + else if (res!=(DWORD)writeLen)
1.1043 + err=KMMCErrGeneral;
1.1044 + else
1.1045 + err=KMMCErrNone;
1.1046 + }
1.1047 +
1.1048 + if (err!=KMMCErrNone)
1.1049 + return(err);
1.1050 + if (writeLen != cmd.iTotalLength)
1.1051 + return KMMCErrDataTimeOut;
1.1052 + }
1.1053 + break;
1.1054 +
1.1055 + case ECmdAppCmd:
1.1056 + // targetCard == -1 when ACMD41 being sent because not yet supplied
1.1057 + if (iAddressedCard != KBroadcastToAllCards)
1.1058 + {
1.1059 + // timeout if addressed card is not SD
1.1060 + if (! iCardInfo[iAddressedCard]->iIsSDCard)
1.1061 + rto = ETrue;
1.1062 + }
1.1063 + else
1.1064 + {
1.1065 + // request sent to specific non-SD card
1.1066 + if (targetCard != -1 && ! iCardInfo[targetCard]->iIsSDCard)
1.1067 + rto = ETrue;
1.1068 + }
1.1069 + break;
1.1070 +
1.1071 + case ECmdSendCSD:
1.1072 + {
1.1073 + iCardInfo[targetCard]->GetCSD(cmd.iResponse);
1.1074 + break;
1.1075 + }
1.1076 +
1.1077 + // ------------------------------------------------------------------
1.1078 + case ECmdLockUnlock:
1.1079 + // in EPOC, Lock() does not actually lock the card. It just sets the
1.1080 + // password. This means that the card is still accessible to the user,
1.1081 + // but must be unlocked the next time it is powered up.
1.1082 +
1.1083 + // a real card will transiently go into rcv and prg state while processing
1.1084 + // this command. When finished, it will fall back into tran state.
1.1085 + // The R1 response is sent immediately after CMD42. CIMReadWriteBlocksSM()
1.1086 + // sends CMD13 to find out whether or not LOCK_UNLOCK_FAIL was set.
1.1087 +
1.1088 + // the asserts in this case protect against invalid data being sent from the
1.1089 + // media driver. A real card would fail these corrupt data blocks.
1.1090 +
1.1091 + {
1.1092 + const TInt8 cmd_byte(*cmd.iDataMemoryP);
1.1093 + __ASSERT_DEBUG( // ensure not CLR_PWD && SET_PWD
1.1094 + !((cmd_byte & KMMCLockUnlockClrPwd) && (cmd_byte & KMMCLockUnlockSetPwd)),
1.1095 + DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCCorruptCommand) );
1.1096 +
1.1097 + __ASSERT_DEBUG( // not actually lock a card
1.1098 + !(cmd_byte & KMMCLockUnlockLockUnlock),
1.1099 + DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCLockAttempt) );
1.1100 +
1.1101 + if (cmd_byte & KMMCLockUnlockErase) // ERASE (not supported)
1.1102 + return KMMCErrNotSupported;
1.1103 +
1.1104 + const TInt8 pwd_len = *(cmd.iDataMemoryP + 1);
1.1105 + const TPtrC8 pwd(cmd.iDataMemoryP + 2, pwd_len);
1.1106 +
1.1107 + if ((cmd_byte & KMMCLockUnlockClrPwd) != 0) // CLR_PWD == 1
1.1108 + {
1.1109 + __ASSERT_DEBUG(
1.1110 + pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
1.1111 + DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCCorruptCommand));
1.1112 +
1.1113 + if (iCardInfo[targetCard]->iIsLocked) // clear when locked
1.1114 + nextCMD42Failed = ETrue;
1.1115 + else // clear when unlocked
1.1116 + {
1.1117 + if (iCardInfo[targetCard]->iPWD->Compare(pwd) != 0) // clear when unlocked with wrong password
1.1118 + nextCMD42Failed = ETrue;
1.1119 + else // clear when unlocked with right password
1.1120 + {
1.1121 + // Clear from password store
1.1122 + iCardInfo[targetCard]->iPWD->Zero();
1.1123 + iCardInfo[targetCard]->iIsLocked = EFalse;
1.1124 + nextCMD42Failed = EFalse;
1.1125 +
1.1126 + // Clear from environment settings
1.1127 + TInt cardNum=(targetCard==0) ? *Wins::CurrentPBusDevicePtr() : 0; // Can't be -1 at this stage
1.1128 + SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[targetCard]->iPWD));
1.1129 + }
1.1130 + }
1.1131 + }
1.1132 + else if ((cmd_byte & KMMCLockUnlockSetPwd) == 0) // SET_PWD == 0: unlock
1.1133 + {
1.1134 + __ASSERT_DEBUG(
1.1135 + pwd_len >= 0 && pwd_len <= KMaxMediaPassword,
1.1136 + DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCCorruptCommand) );
1.1137 +
1.1138 + if (! iCardInfo[targetCard]->iIsLocked) // unlock when unlocked
1.1139 + nextCMD42Failed = ETrue;
1.1140 + else
1.1141 + {
1.1142 + if (iCardInfo[targetCard]->iPWD->Compare(pwd) != 0) // unlock when locked with wrong password
1.1143 + nextCMD42Failed = ETrue;
1.1144 + else // unlock when locked with right password
1.1145 + {
1.1146 + iCardInfo[targetCard]->iIsLocked = EFalse;
1.1147 + nextCMD42Failed = EFalse;
1.1148 + }
1.1149 + }
1.1150 + }
1.1151 + else /* ((cmd_byte & KMMCLockUnlockSetPwd) != 0) */ // SET_PWD == 1
1.1152 + {
1.1153 + __ASSERT_DEBUG(
1.1154 + cmd_byte & KMMCLockUnlockSetPwd,
1.1155 + DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCCorruptCommand) );
1.1156 +
1.1157 + // if pwd_len < iCardInfo[targetCard]->iPWD->Length() then data block must be invalid.
1.1158 + // This can be caused by bad user input rather than inaccurate formation.
1.1159 + if (!( pwd_len >= iCardInfo[targetCard]->iPWD->Length()
1.1160 + && pwd_len <= iCardInfo[targetCard]->iPWD->Length() + KMaxMediaPassword ))
1.1161 + {
1.1162 + nextCMD42Failed = ETrue;
1.1163 + }
1.1164 + else
1.1165 + {
1.1166 + const TInt old_pwd_len = iCardInfo[targetCard]->iPWD->Length();
1.1167 + TPtrC8 old_pwd(cmd.iDataMemoryP + 2, old_pwd_len);
1.1168 + TPtrC8 new_pwd(cmd.iDataMemoryP + 2 + old_pwd_len, pwd_len - old_pwd_len);
1.1169 +
1.1170 + // card must not be locked and supplied current password must be correct
1.1171 + if (iCardInfo[targetCard]->iIsLocked || iCardInfo[targetCard]->iPWD->Compare(old_pwd) != 0)
1.1172 + nextCMD42Failed = ETrue;
1.1173 + else
1.1174 + {
1.1175 + // Set in password store
1.1176 + iCardInfo[targetCard]->iPWD->Copy(new_pwd);
1.1177 + nextCMD42Failed = EFalse;
1.1178 +
1.1179 + // Set in environment settings
1.1180 + TInt cardNum=(targetCard==0) ? *Wins::CurrentPBusDevicePtr() : 0; // Can't be -1 at this stage
1.1181 + SetMediaPasswordEnvironmentVar(MMCSocket()->iSocketNumber,cardNum,*(iCardInfo[targetCard]->iPWD));
1.1182 + }
1.1183 + }
1.1184 + } // else /* ((cmd_byte & KMMCLockUnlockSetPwd) != 0) */
1.1185 + } // case ECmdLockUnlock
1.1186 + break;
1.1187 +
1.1188 + // ------------------------------------------------------------------
1.1189 + case ECmd5:
1.1190 + {
1.1191 + if (!iCardInfo[iAddressedCard]->iIsSDCard)
1.1192 + {
1.1193 + rto = ETrue;
1.1194 + }
1.1195 + else
1.1196 + {
1.1197 + // bit31 is set to indicate cards are not still powering up
1.1198 + TUint32 r5 = 0;
1.1199 +
1.1200 + r5 |= KWinsSdioFunctionCount << KSDIOFunctionCountShift;
1.1201 + r5 |= KWinsSdioMemoryPresent ? KSDIOMemoryPresent : 0;
1.1202 + r5 |= KMMCWinsCardOCRValue;
1.1203 + r5 |= KSDIOReady;
1.1204 +
1.1205 + TMMC::BigEndian4Bytes(cmd.iResponse, r5);
1.1206 + }
1.1207 + }
1.1208 + break;
1.1209 +
1.1210 + case ECmd52:
1.1211 + {
1.1212 + if (!iCardInfo[iAddressedCard]->iIsSDCard)
1.1213 + {
1.1214 + rto = ETrue;
1.1215 + }
1.1216 + else
1.1217 + {
1.1218 + const TUint32 address = (cmd.iArgument >> KSdioCmdAddressShift) & KSdioCmdAddressMask;
1.1219 + const TUint32 function = (cmd.iArgument >> KSdioCmdFunctionShift) & KSdioCmdFunctionMask;
1.1220 +
1.1221 + const TUint32 ioAddress = address + (0x100*function);
1.1222 +
1.1223 + const SRegisterMapInfo* entry = NULL;
1.1224 + entry = FindIoEntryFromAddress(IoMapTop, ioAddress);
1.1225 +
1.1226 + if(!entry)
1.1227 + {
1.1228 + rto = ETrue;
1.1229 + }
1.1230 + else
1.1231 + {
1.1232 + if((cmd.iArgument & KSdioCmdDirMask) == KSdioCmdRead)
1.1233 + {
1.1234 + TUint8 dataVal = 0;
1.1235 + if(entry->iAccessFunction)
1.1236 + {
1.1237 + entry->iAccessFunction(targetCard, entry->iRegisterID, this, ETrue, dataVal);
1.1238 + }
1.1239 +
1.1240 + if(entry->iDataP)
1.1241 + {
1.1242 + TUint entryOffset = ioAddress - entry->iAddress;
1.1243 + if(entryOffset >= 0 && entryOffset < entry->iLength)
1.1244 + {
1.1245 + dataVal = ((TUint8*)entry->iDataP)[entryOffset];
1.1246 + }
1.1247 + }
1.1248 +
1.1249 + TUint32 r5 = 0;
1.1250 +
1.1251 + r5 |= dataVal;
1.1252 + r5 |= 0x1000;
1.1253 +
1.1254 + TMMC::BigEndian4Bytes(cmd.iResponse, r5);
1.1255 + }
1.1256 + else
1.1257 + {
1.1258 + const TBool raw = (cmd.iArgument & KSdioCmdRAW) ? ETrue : EFalse;
1.1259 + TUint8 data = (TUint8)(cmd.iArgument & KSdioCmdDataMask);
1.1260 +
1.1261 + if(entry->iDataP)
1.1262 + {
1.1263 + *(TUint8*)(entry->iDataP) &= ~(entry->iFlags);
1.1264 + *(TUint8*)(entry->iDataP) |= (data & entry->iFlags);
1.1265 + }
1.1266 +
1.1267 + if(entry->iAccessFunction)
1.1268 + {
1.1269 + entry->iAccessFunction(targetCard, entry->iRegisterID, this, EFalse, data);
1.1270 + }
1.1271 +
1.1272 + TUint32 r5 = 0;
1.1273 +
1.1274 + if(raw)
1.1275 + {
1.1276 + r5 |= data;
1.1277 + }
1.1278 +
1.1279 +// r5 |= 0x1000;
1.1280 + r5 |= 0x2000;
1.1281 +
1.1282 + TMMC::BigEndian4Bytes(cmd.iResponse, r5);
1.1283 + }
1.1284 + }
1.1285 + }
1.1286 + }
1.1287 + break;
1.1288 +
1.1289 + case ECmd53:
1.1290 + {
1.1291 + TBool a = EFalse;
1.1292 + if(a)
1.1293 + {
1.1294 + return(KMMCErrDataTimeOut);
1.1295 + }
1.1296 +
1.1297 + if (!iCardInfo[iAddressedCard]->iIsSDCard)
1.1298 + {
1.1299 + rto = ETrue;
1.1300 + }
1.1301 + else
1.1302 + {
1.1303 + const TUint32 address = (cmd.iArgument >> KSdioCmdAddressShift) & KSdioCmdAddressMask;
1.1304 + const TUint32 function = (cmd.iArgument >> KSdioCmdFunctionShift) & KSdioCmdFunctionMask;
1.1305 +
1.1306 + const TUint32 ioAddress = address + (0x100*function);
1.1307 +
1.1308 + if((cmd.iArgument & KSdioCmdBlockMode) == KSdioCmdBlockMode)
1.1309 + {
1.1310 + // Block mode not supported (yet)
1.1311 + rto = ETrue;
1.1312 + }
1.1313 + else
1.1314 + {
1.1315 + TUint32 byteCount = cmd.iArgument & KSdioCmdCountMask;
1.1316 + TUint32 count = 0;
1.1317 + TUint32 currentAddress = ioAddress;
1.1318 +
1.1319 + TUint32 inc = ((cmd.iArgument & KSdioCmdAutoInc) == KSdioCmdAutoInc) ? 1 : 0;
1.1320 +
1.1321 + while(count < byteCount)
1.1322 + {
1.1323 + const SRegisterMapInfo* entry = NULL;
1.1324 + entry = FindIoEntryFromAddress(IoMapTop, currentAddress);
1.1325 +
1.1326 + if(entry)
1.1327 + {
1.1328 + if((cmd.iArgument & KSdioCmdDirMask) == KSdioCmdRead)
1.1329 + {
1.1330 + TUint8 dataVal = 0;
1.1331 + if(entry->iAccessFunction)
1.1332 + {
1.1333 + entry->iAccessFunction(targetCard, entry->iRegisterID, this, ETrue, dataVal);
1.1334 + }
1.1335 +
1.1336 + if(entry->iDataP)
1.1337 + {
1.1338 + TUint entryOffset = currentAddress - entry->iAddress;
1.1339 + if(entryOffset >= 0 && entryOffset < entry->iLength)
1.1340 + {
1.1341 + dataVal = ((TUint8*)entry->iDataP)[entryOffset];
1.1342 + }
1.1343 + }
1.1344 +
1.1345 + cmd.iDataMemoryP[count] = dataVal;
1.1346 + }
1.1347 + else
1.1348 + {
1.1349 + TUint8 data = cmd.iDataMemoryP[count];
1.1350 +
1.1351 + if(entry->iDataP)
1.1352 + {
1.1353 + TUint entryOffset = currentAddress - entry->iAddress;
1.1354 + if(entryOffset >= 0 && entryOffset < entry->iLength)
1.1355 + {
1.1356 + ((TUint8*)entry->iDataP)[entryOffset] &= ~(entry->iFlags);
1.1357 + ((TUint8*)entry->iDataP)[entryOffset] |= (data & entry->iFlags);
1.1358 + }
1.1359 +
1.1360 + }
1.1361 +
1.1362 + if(entry->iAccessFunction)
1.1363 + {
1.1364 + entry->iAccessFunction(targetCard, entry->iRegisterID, this, EFalse, data);
1.1365 + }
1.1366 + }
1.1367 + }
1.1368 +
1.1369 + count++;
1.1370 + currentAddress += inc;
1.1371 + }
1.1372 +
1.1373 + TUint32 r5 = 0;
1.1374 +
1.1375 +// r5 |= 0x2000;
1.1376 + r5 |= 0x1000;
1.1377 +
1.1378 + TMMC::BigEndian4Bytes(cmd.iResponse, r5);
1.1379 + }
1.1380 + }
1.1381 + }
1.1382 + break;
1.1383 +
1.1384 + // ------------------------------------------------------------------
1.1385 + default:
1.1386 + break;
1.1387 + }
1.1388 +
1.1389 + if (rto)
1.1390 + return(KMMCErrResponseTimeOut);
1.1391 +
1.1392 + cmd.iCommand = origCmd;
1.1393 + // If this is an R1 or R1b response type command then return card status as a response
1.1394 + if ( targetCard != -1
1.1395 + && (cmd.iSpec.iResponseType==ERespTypeR1 || cmd.iSpec.iResponseType==ERespTypeR1B) )
1.1396 + {
1.1397 + TUint32 resp(
1.1398 + iCardInfo[targetCard]->iState
1.1399 + | ((iCardInfo[targetCard]->iIsLocked ? 1 : 0) << 25)
1.1400 + | ((lock_unlock_failed ? 1 : 0) << 24) );
1.1401 +
1.1402 + if (iCMD42Failed) // previous CMD42
1.1403 + {
1.1404 + resp |= KMMCStatErrLockUnlock;
1.1405 + nextCMD42Failed = EFalse;
1.1406 + }
1.1407 + iCMD42Failed = nextCMD42Failed;
1.1408 + TMMC::BigEndian4Bytes(&cmd.iResponse[0],resp); // Ignore bits 47-40
1.1409 + }
1.1410 + SMF_END
1.1411 + }
1.1412 +
1.1413 +TInt DWinsSDIOStack::AccessIoEnable(TInt /*aTargetCard*/, TInt /*aVal*/, TAny* aSelfP, TBool aRead, TUint8& aData)
1.1414 +//
1.1415 +// Access the IO Enable register
1.1416 +//
1.1417 + {
1.1418 + DWinsSDIOStack& self = *(DWinsSDIOStack*)aSelfP;
1.1419 +
1.1420 + if(aRead)
1.1421 + {
1.1422 + aData = GCCCRRegIoEnable;
1.1423 + }
1.1424 + else
1.1425 + {
1.1426 + TUint8 mask = 0;
1.1427 + for(TInt i=0; i<KWinsSdioFunctionCount; i++)
1.1428 + {
1.1429 + mask |= (0x02 << i);
1.1430 + }
1.1431 +
1.1432 + aData &= mask;
1.1433 +
1.1434 + // Disable functions first...
1.1435 + GFunctionToEnable &= aData;
1.1436 + GCCCRRegIoReady &= aData;
1.1437 + GCCCRRegIoEnable &= aData;
1.1438 +
1.1439 + // Enabling any functions - This uses the delayed timer...
1.1440 + if((GCCCRRegIoEnable & aData) != aData)
1.1441 + {
1.1442 + GFunctionToEnable = GCCCRRegIoEnable ^ aData;
1.1443 + GCCCRRegIoEnable |= GFunctionToEnable;
1.1444 +
1.1445 + self.iEnableTimer.OneShot(KFunctionEnableDelay_uS / NKern::TickPeriod());
1.1446 + }
1.1447 + }
1.1448 +
1.1449 + return(KErrNone);
1.1450 + }
1.1451 +
1.1452 +void DWinsSDIOStack::EnableTimerCallback(TAny* /*aSelfP*/)
1.1453 + {
1.1454 + GCCCRRegIoReady |= GFunctionToEnable;
1.1455 + }
1.1456 +
1.1457 +TInt DWinsSDIOStack::AccessCsaWindow(TInt aTargetCard, TInt /*aVal*/, TAny* aSelfP, TBool aRead, TUint8& aData)
1.1458 +//
1.1459 +// Access the CSA Windoe
1.1460 +//
1.1461 + {
1.1462 + TMMCErr err = KErrNone;
1.1463 +
1.1464 + DWinsSDIOStack& self = *(DWinsSDIOStack*)aSelfP;
1.1465 +
1.1466 + HANDLE winHandle = self.iCardInfo[aTargetCard]->iAreaHandles[KSDIOArea];
1.1467 +
1.1468 + if (SetFilePointer(winHandle, GFBR1RegCsaPtr, NULL,FILE_BEGIN) == 0xffffffffu)
1.1469 + err = MapLastErrorMmc();
1.1470 + else
1.1471 + {
1.1472 + DWORD res;
1.1473 + TUint8 val = 0;
1.1474 + TUint len = 1;
1.1475 +
1.1476 + BOOL rwRes = FALSE;
1.1477 +
1.1478 + if(aRead)
1.1479 + {
1.1480 + rwRes = ReadFile(winHandle, (TAny*)&val, len, &res, NULL);
1.1481 + }
1.1482 + else
1.1483 + {
1.1484 + val = aData;
1.1485 + rwRes = WriteFile(winHandle, (TAny*)&val, len, &res, NULL);
1.1486 + }
1.1487 +
1.1488 + if(rwRes == FALSE)
1.1489 + {
1.1490 + err = MapLastErrorMmc();
1.1491 + }
1.1492 + else if(res != len)
1.1493 + {
1.1494 + err = KMMCErrGeneral;
1.1495 + }
1.1496 + else
1.1497 + {
1.1498 + if(aRead)
1.1499 + {
1.1500 + aData = val;
1.1501 + }
1.1502 +
1.1503 + GFBR1RegCsaPtr++;
1.1504 + err = KMMCErrNone;
1.1505 + }
1.1506 + }
1.1507 +
1.1508 + return(err);
1.1509 + }
1.1510 +
1.1511 +TInt DWinsSDIOStack::AccessCsaPointer(TInt /*aTargetCard*/, TInt aVal, TAny* /*aSelfP*/, TBool aRead, TUint8& aData)
1.1512 +//
1.1513 +// Access the CSA Windoe
1.1514 +//
1.1515 + {
1.1516 + TInt err = KErrNone;
1.1517 +
1.1518 + TUint32 mask = 0;
1.1519 + TUint32 shift = 0;
1.1520 +
1.1521 + switch(aVal)
1.1522 + {
1.1523 + case KFBRRegCsaPtrLo:
1.1524 + {
1.1525 + mask = 0x0000FF;
1.1526 + shift = 0;
1.1527 + break;
1.1528 + }
1.1529 +
1.1530 + case KFBRRegCsaPtrMid:
1.1531 + {
1.1532 + mask = 0x00FF00;
1.1533 + shift = 8;
1.1534 + break;
1.1535 + }
1.1536 +
1.1537 + case KFBRRegCsaPtrHi:
1.1538 + {
1.1539 + mask = 0xFF0000;
1.1540 + shift = 16;
1.1541 + break;
1.1542 + }
1.1543 +
1.1544 + default:
1.1545 + {
1.1546 + err = KErrNotSupported;
1.1547 + break;
1.1548 + }
1.1549 + }
1.1550 +
1.1551 + if(err == KErrNone)
1.1552 + {
1.1553 + if(aRead)
1.1554 + {
1.1555 + aData = (TUint8)((GFBR1RegCsaPtr & mask) >> shift);
1.1556 + }
1.1557 + else
1.1558 + {
1.1559 + GFBR1RegCsaPtr &= ~mask;
1.1560 + GFBR1RegCsaPtr |= (TUint32)aData << shift;
1.1561 + }
1.1562 + }
1.1563 +
1.1564 + return(err);
1.1565 + }
1.1566 +
1.1567 +void DWinsSDIOStack::EnableSDIOInterrupt(TBool /*aEnable*/)
1.1568 +//
1.1569 +// Virtual
1.1570 +//
1.1571 + {
1.1572 + }
1.1573 +
1.1574 +void DWinsSDIOStack::SetBusWidth(TUint32 /*aBusWidth*/)
1.1575 +//
1.1576 +// Virtual
1.1577 +//
1.1578 + {
1.1579 + }
1.1580 +
1.1581 +TUint32 DWinsSDIOStack::MaxBlockSize() const
1.1582 +//
1.1583 +// Virtual
1.1584 +//
1.1585 + {
1.1586 + return(512);
1.1587 + }
1.1588 +
1.1589 +
1.1590 +TInt DWinsSDIOStack::FindAnyCardInStack(TMMCardStateEnum aState)
1.1591 +//
1.1592 +// first first active card in supplied state. Return -1 if
1.1593 +// no active card is in supplied state.
1.1594 +//
1.1595 + {
1.1596 + if (iAddressedCard != KBroadcastToAllCards)
1.1597 + return (iCardInfo[iAddressedCard]->iState == aState) ? iAddressedCard : -1;
1.1598 + else
1.1599 + {
1.1600 + for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
1.1601 + {
1.1602 + if (iCardInfo[i]->iState == aState)
1.1603 + return i;
1.1604 + }
1.1605 +
1.1606 + return -1;
1.1607 + }
1.1608 + }
1.1609 +
1.1610 +TInt DWinsSDIOStack::FindFirstCardInStack(TMMCardStateEnum aState)
1.1611 +//
1.1612 +// find card which is active on bus and in supplied state.
1.1613 +// There can be more than one active card in the the supplied state,
1.1614 +// but there should be at least one.
1.1615 +//
1.1616 + {
1.1617 + if (iAddressedCard != KBroadcastToAllCards)
1.1618 + {
1.1619 + __ASSERT_DEBUG(iCardInfo[iAddressedCard]->iState == aState, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFFCNotSelCard));
1.1620 + return iAddressedCard;
1.1621 + }
1.1622 + else
1.1623 + {
1.1624 + TInt idx = -1;
1.1625 + for (TInt i = 0; idx != -1 && i < KTotalWinsCardSlots; ++i)
1.1626 + {
1.1627 + if (iCardInfo[i]->iState == aState)
1.1628 + idx = i;
1.1629 + }
1.1630 +
1.1631 + __ASSERT_DEBUG(idx != -1, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFFCNoneSel));
1.1632 + return idx;
1.1633 + }
1.1634 + }
1.1635 +
1.1636 +TInt DWinsSDIOStack::FindOneCardInStack(TMMCardStateEnum aState)
1.1637 +//
1.1638 +// find card which is active on bus and in supplied state.
1.1639 +// There should be exactly one active card in the supplied state.
1.1640 +//
1.1641 + {
1.1642 + if (iAddressedCard != KBroadcastToAllCards)
1.1643 + {
1.1644 + __ASSERT_DEBUG(iCardInfo[iAddressedCard]->iState == aState, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFOCNotSelCard));
1.1645 + return iAddressedCard;
1.1646 + }
1.1647 + else
1.1648 + {
1.1649 + TInt idx = -1;
1.1650 + for (TInt i = 0; i < KTotalWinsCardSlots; ++i)
1.1651 + {
1.1652 + if (iCardInfo[i]->iState == aState)
1.1653 + {
1.1654 + __ASSERT_DEBUG(idx == -1, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFOCMultiSel));
1.1655 + idx = i;
1.1656 + }
1.1657 + }
1.1658 +
1.1659 + __ASSERT_DEBUG(idx != -1, DWinsSDIOStack::Panic(DWinsSDIOStack::EStkFOCNoneSel));
1.1660 + return idx;
1.1661 + }
1.1662 + }
1.1663 +
1.1664 +
1.1665 +// ======== DWinsMMCMediaChange ========
1.1666 +
1.1667 +#pragma warning( disable : 4355 ) // this used in initializer list
1.1668 +DWinsMMCMediaChange::DWinsMMCMediaChange(TInt aMediaChangeNum)
1.1669 + : DMMCMediaChange(aMediaChangeNum),
1.1670 + iDoorClosedCount(0),
1.1671 + iMediaChangeEnable(ETrue),
1.1672 + iStackP(NULL)
1.1673 + {
1.1674 + iMediaDoorCloseReload=2; // Units: In theory-20ms, Actual-100ms
1.1675 + }
1.1676 +#pragma warning( default : 4355 )
1.1677 +
1.1678 +TInt DWinsMMCMediaChange::Create()
1.1679 +//
1.1680 +// Initialiser.
1.1681 +//
1.1682 + {
1.1683 + return(DMediaChangeBase::Create());
1.1684 + }
1.1685 +
1.1686 +void DWinsMMCMediaChange::DoorOpenService()
1.1687 +//
1.1688 +// Handle the media change (this function, never postponed is called on media
1.1689 +// change interrupt).
1.1690 +//
1.1691 + {
1.1692 + Disable(); // Disable interrupt until door closes again.
1.1693 + iDoorOpenDfc.Enque();
1.1694 + }
1.1695 +
1.1696 +void DWinsMMCMediaChange::DoDoorOpen()
1.1697 +//
1.1698 +// Handle media door open (called on media door open interrupt).
1.1699 +//
1.1700 + {
1.1701 + iDoorClosedCount=iMediaDoorCloseReload;
1.1702 + // Just start a ticklink to poll for door closing
1.1703 + iTickLink.Periodic(KMediaChangeTickInterval,DWinsMMCMediaChange::Tick,this);
1.1704 + }
1.1705 +
1.1706 +void DWinsMMCMediaChange::DoDoorClosed()
1.1707 +//
1.1708 +// Handle media door closing (called on media door open interrupt).
1.1709 +//
1.1710 + {
1.1711 +
1.1712 + iTickLink.Cancel(); // Doesn't matter if wasn't enabled
1.1713 + Enable(); // Re-enable door interrupts
1.1714 +
1.1715 + // While the door was open the user may have changed the card in slot 0
1.1716 + if (iStackP && *Wins::CurrentPBusDevicePtr()>=0)
1.1717 + iStackP->iCardInfo[0]=iStackP->iCardPool[*Wins::CurrentPBusDevicePtr()];
1.1718 + }
1.1719 +
1.1720 +void DWinsMMCMediaChange::ForceMediaChange()
1.1721 +//
1.1722 +// Force media change
1.1723 +//
1.1724 + {
1.1725 + DoorOpenService();
1.1726 + }
1.1727 +
1.1728 +TMediaState DWinsMMCMediaChange::MediaState()
1.1729 +//
1.1730 +// Return status of media changed signal.
1.1731 +//
1.1732 + {
1.1733 +
1.1734 + if (iDoorClosedCount>0)
1.1735 + return(EDoorOpen);
1.1736 + return( (*Wins::MediaDoorOpenPtr())?EDoorOpen:EDoorClosed);
1.1737 + }
1.1738 +
1.1739 +void DWinsMMCMediaChange::Tick(TAny *aPtr)
1.1740 +//
1.1741 +// Called on the tick to poll for door closing (called on DFC).
1.1742 +//
1.1743 + {
1.1744 +
1.1745 + ((DWinsMMCMediaChange*)aPtr)->TickService();
1.1746 + }
1.1747 +
1.1748 +void DWinsMMCMediaChange::TickService()
1.1749 +//
1.1750 +// Called on the tick to poll for door closing (called on DFC).
1.1751 +//
1.1752 + {
1.1753 +
1.1754 + __ASSERT_DEBUG(iDoorClosedCount>=0,DWinsSDIOStack::Panic(DWinsSDIOStack::EWinsMMCMediaChangeTickFault));
1.1755 + if (!(*Wins::MediaDoorOpenPtr()))
1.1756 + {
1.1757 + if (iDoorClosedCount > 0)
1.1758 + iDoorClosedCount--;
1.1759 + if (iDoorClosedCount == 0)
1.1760 + DoorClosedService();
1.1761 + }
1.1762 + else
1.1763 + iDoorClosedCount=iMediaDoorCloseReload; // Door open so start again.
1.1764 + }
1.1765 +
1.1766 +void DWinsMMCMediaChange::Enable()
1.1767 +//
1.1768 +// Enable media change
1.1769 +//
1.1770 + {
1.1771 +
1.1772 + iMediaChangeEnable=ETrue;
1.1773 + }
1.1774 +
1.1775 +void DWinsMMCMediaChange::Disable()
1.1776 +//
1.1777 +// Disable media change
1.1778 +//
1.1779 + {
1.1780 +
1.1781 + iMediaChangeEnable=EFalse;
1.1782 + }
1.1783 +
1.1784 +void DWinsMMCMediaChange::MediaChangeCallBack(TAny *aPtr)
1.1785 +//
1.1786 +// Static called on media change
1.1787 +//
1.1788 + {
1.1789 +
1.1790 + DWinsMMCMediaChange* mc=(DWinsMMCMediaChange*)aPtr;
1.1791 + if (mc!=NULL&&mc->iMediaChangeEnable)
1.1792 + mc->DoorOpenService();
1.1793 + }
1.1794 +
1.1795 +
1.1796 +// ======== TWinsCardInfo ========
1.1797 +
1.1798 +void TWinsCardInfo::GetCSD(TUint8* aResp) const
1.1799 + {
1.1800 + // Bits 127-96
1.1801 + TUint32 csd=(0x1<<30); /* CSD_STRUCTURE: CSD Version No 1.1 */
1.1802 + csd|= (0x2<<26); /* SPEC_VERS: Version 2.1 */
1.1803 + csd|= (0x0E<<16); /* TAAC: 1mS */
1.1804 + csd|= (0x0A<<8); /* NSAC: 1000 */
1.1805 + csd|= (0x59); /* TRAN_SPEED: 5.0Mbit/s */
1.1806 + TMMC::BigEndian4Bytes(&aResp[0],csd);
1.1807 + // Bits 95-64
1.1808 + const TUint32 ccc =
1.1809 + KMMCCmdClassBasic | KMMCCmdClassBlockRead
1.1810 + | KMMCCmdClassBlockWrite | KMMCCmdClassLockCard;
1.1811 + csd= (ccc<<20); /* CCC: classes 0, 2, 4, and 7 */
1.1812 + csd|= (0x9<<16); /* READ_BL_LEN: 512 bytes */
1.1813 + csd|= (0x0<<15); /* READ_BL_PARTIAL: No */
1.1814 + csd|= (0x0<<14); /* WRITE_BLK_MISALIGN: No */
1.1815 + csd|= (0x0<<13); /* READ_BLK_MISALIGN: No */
1.1816 + csd|= (0x0<<12); /* DSR_IMP: No DSR */
1.1817 + csd|= (0x0<<8); /* C_SIZE: 1Mb */
1.1818 + csd|= (0x7F); /* C_SIZE: 1Mb (cont)*/
1.1819 + TMMC::BigEndian4Bytes(&aResp[4],csd);
1.1820 + // Bits 63-32
1.1821 + csd= (3UL<<30); /* C_SIZE: 2Mb (cont) */
1.1822 + csd|= (0x1<<27); /* VDD_R_CURR_MIN: 1mA */
1.1823 + csd|= (0x1<<24); /* VDD_R_CURR_MAX: 5mA */
1.1824 + csd|= (0x2<<21); /* VDD_W_CURR_MIN: 5mA */
1.1825 + csd|= (0x3<<18); /* VDD_W_CURR_MAX: 25mA */
1.1826 + csd|= (0x0<<15); /* C_SIZE_MULT: 0 */
1.1827 + if (! iIsSDCard)
1.1828 + {
1.1829 + csd|= (0x0<<10); /* SECTOR_SIZE: 1 write block */
1.1830 + csd|= (0x0<<5); /* ERASE_GRP_SIZE: 1 sector */
1.1831 + csd|= (0x0); /* WP_GRP_SIZE: 1 erase group */
1.1832 + }
1.1833 + else
1.1834 + {
1.1835 + csd |= (0x00 << (46 - 32)); // ERASE_BLK_EN
1.1836 + csd |= (0x1f << (39 - 32)); // SECTOR_SIZE: 32 write blocks
1.1837 + csd |= (0x00 << (32 - 32)); // WP_GRP_SIZE: 1 erase sector.
1.1838 + }
1.1839 + TMMC::BigEndian4Bytes(&aResp[8],csd);
1.1840 + // Bits 31-0
1.1841 + csd= (0x0<<31); /* WP_GRP_ENABLE: No */
1.1842 + csd|= (0x0<<29); /* DEFAULT_ECC: ? */
1.1843 + csd|= (0x3<<26); /* R2W_FACTOR: 8 */
1.1844 + csd|= (0x9<<22); /* WRITE_BL_LEN: 512 bytes */
1.1845 + csd|= (0x0<<21); /* WRITE_BL_PARTIAL: No */
1.1846 + csd|= (0x0<<15); /* FILE_FORMAT_GRP: Hard disk */
1.1847 + csd|= (0x0<<14); /* COPY: original */
1.1848 + csd|= (0x0<<13); /* PERM_WRITE_PROTECT: No */
1.1849 + csd|= (0x0<<12); /* TMP_WRITE_PROTECT: No */
1.1850 + csd|= (0x0<<10); /* FILE_FORMAT: Hard disk */
1.1851 + csd|= (0x0<<8); /* ECC: None */
1.1852 + csd|= (0x0<<1); /* CRC: ? */
1.1853 + csd|= (0x1); /* not used */
1.1854 + TMMC::BigEndian4Bytes(&aResp[12],csd);
1.1855 + }
1.1856 +
1.1857 +// ======== DWinsSDIOPsu ========
1.1858 +
1.1859 +
1.1860 +DWinsSDIOPsu::DWinsSDIOPsu(TInt aVccNum, TInt aMcId)
1.1861 + : DSDIOPsu(aVccNum, aMcId)
1.1862 + {}
1.1863 +
1.1864 +void DWinsSDIOPsu::Init()
1.1865 +//
1.1866 +// Initialise the PSU
1.1867 +//
1.1868 + {
1.1869 + // Nothing to do
1.1870 + }
1.1871 +
1.1872 +void DWinsSDIOPsu::DoSetState(TPBusPsuState aState)
1.1873 +//
1.1874 +// Turn on/off the PSU. If it is possible to adjust the output voltage on this
1.1875 +// PSU then retreive the required voltage level from TMMCPsu::iVoltageSetting
1.1876 +// (which is in OCR register format).
1.1877 +//
1.1878 + {
1.1879 +
1.1880 + switch (aState)
1.1881 + {
1.1882 + case EPsuOff:
1.1883 + break;
1.1884 + case EPsuOnFull:
1.1885 + break;
1.1886 + case EPsuOnCurLimit:
1.1887 + break;
1.1888 + }
1.1889 + }
1.1890 +
1.1891 +TInt DWinsSDIOPsu::VoltageInMilliVolts()
1.1892 +//
1.1893 +// Return the level of the PSU (in mV) or -ve if error.
1.1894 +//
1.1895 + {
1.1896 +
1.1897 + return(0);
1.1898 + }
1.1899 +
1.1900 +void DWinsSDIOPsu::DoCheckVoltage()
1.1901 +//
1.1902 +// Check the voltage level of the PSU is as expected. Returns either KErrNone, KErrGeneral
1.1903 +// to indicate the pass/fail state or KErrNotReady if the voltage check isn't complete.
1.1904 +//
1.1905 + {
1.1906 +
1.1907 + ReceiveVoltageCheckResult(KErrNone);
1.1908 + }
1.1909 +
1.1910 +void DWinsSDIOPsu::PsuInfo(TPBusPsuInfo &anInfo)
1.1911 +//
1.1912 +// Return machine info relating to the MMC PSU supply
1.1913 +//
1.1914 + {
1.1915 +
1.1916 + anInfo.iVoltageSupported=0x00040000; // 3.0V (OCR reg. format).
1.1917 + anInfo.iMaxCurrentInMicroAmps=0;
1.1918 + anInfo.iVoltCheckInterval=0;
1.1919 + anInfo.iVoltCheckMethod=EPsuChkComparator;
1.1920 +
1.1921 + anInfo.iNotLockedTimeOut=5;
1.1922 + anInfo.iInactivityTimeOut=10;
1.1923 + }