|
1 // Copyright (c) 1999-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 the License "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 // Media driver for MultiMediaCard Flash device |
|
15 // |
|
16 // |
|
17 |
|
18 #include "mmc.h" |
|
19 #include "pbusmedia.h" |
|
20 #include <drivers/emmcptn.h> |
|
21 |
|
22 #if defined(__DEMAND_PAGING__) |
|
23 // If in debug mode, enable paging stats and their retrieval using DLocalDrive::EControlIO |
|
24 #if defined( _DEBUG) |
|
25 #define __TEST_PAGING_MEDIA_DRIVER__ |
|
26 #endif |
|
27 #include "mmcdp.h" |
|
28 #endif |
|
29 |
|
30 #ifndef BTRACE_PAGING_MEDIA |
|
31 #undef BTraceContext8 |
|
32 #define BTraceContext8(aCategory,aSubCategory,a1,a2) |
|
33 #endif // BTRACE_PAGING_MEDIA |
|
34 |
|
35 // Enable this macro to debug cache: |
|
36 // NB The greater the number of blocks, the slower this is... |
|
37 //#define _DEBUG_CACHE |
|
38 #ifdef _DEBUG_CACHE |
|
39 #define __ASSERT_CACHE(c,p) (void)((c)||(p,0)) |
|
40 #else |
|
41 #define __ASSERT_CACHE(c,p) |
|
42 #endif |
|
43 |
|
44 |
|
45 GLREF_C TInt GetMediaDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry, TUint16& aReservedSectors, const TMMCard* aCardP); |
|
46 GLREF_C TBool MBRMandatory(const TMMCard* aCardP); |
|
47 GLREF_C TBool CreateMBRAfterFormat(const TMMCard* aCardP); |
|
48 GLREF_C TInt BlockSize(const TMMCard* aCardP); |
|
49 GLREF_C TInt EraseBlockSize(const TMMCard* aCardP); |
|
50 GLREF_C TInt GetCardFormatInfo(const TMMCard* aCardP, TLDFormatInfo& aFormatInfo); |
|
51 |
|
52 const TInt KStackNumber = 0; |
|
53 |
|
54 const TInt KDiskSectorSize=512; |
|
55 const TInt KDiskSectorShift=9; |
|
56 |
|
57 const TInt KIdleCurrentInMilliAmps = 1; |
|
58 |
|
59 const TInt KMBRFirstPartitionEntry=0x1BE; |
|
60 |
|
61 template <class T> |
|
62 inline T UMin(T aLeft,T aRight) |
|
63 {return(aLeft<aRight ? aLeft : aRight);} |
|
64 |
|
65 |
|
66 class DPhysicalDeviceMediaMmcFlash : public DPhysicalDevice |
|
67 { |
|
68 public: |
|
69 DPhysicalDeviceMediaMmcFlash(); |
|
70 |
|
71 virtual TInt Install(); |
|
72 virtual void GetCaps(TDes8& aDes) const; |
|
73 virtual TInt Create(DBase*& aChannel, TInt aMediaId, const TDesC8* aInfo, const TVersion& aVer); |
|
74 virtual TInt Validate(TInt aDeviceType, const TDesC8* aInfo, const TVersion& aVer); |
|
75 virtual TInt Info(TInt aFunction, TAny* a1); |
|
76 }; |
|
77 |
|
78 |
|
79 // these should be static const members of DMmcMediaDriverFlash, but VC doesn't support this |
|
80 const TInt64 KInvalidBlock = -1; |
|
81 const TInt KNoCacheBlock = -1; |
|
82 |
|
83 class DMmcMediaDriverFlash : public DMediaDriver |
|
84 { |
|
85 public: |
|
86 DMmcMediaDriverFlash(TInt aMediaId); |
|
87 ~DMmcMediaDriverFlash(); |
|
88 // ...from DMediaDriver |
|
89 virtual void Close(); |
|
90 // replacing pure virtual |
|
91 virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage*); |
|
92 virtual TInt Request(TLocDrvRequest& aRequest); |
|
93 virtual TInt PartitionInfo(TPartitionInfo& anInfo); |
|
94 virtual void NotifyPowerDown(); |
|
95 virtual void NotifyEmergencyPowerDown(); |
|
96 // For creation by DPhysicalDeviceMediaMmcFlash |
|
97 TInt DoCreate(TInt aMediaId); |
|
98 |
|
99 private: |
|
100 enum TPanic |
|
101 { |
|
102 EDRInUse = 0x0000, EDRStart, EDRNotPositive, EDREnd, |
|
103 ELRRequest = 0x0010, ELRStart, ELRNotPositive, ELREnd, ELRCached, |
|
104 EDWInUse = 0x0020, EDWStart, EDWNotPositive, EDWEnd, |
|
105 EDFInUse = 0x0030, EDFStart, EDFNotPositive, EDFEnd, ENotMmcSocket, |
|
106 ELWRequest = 0x0040, ELWStart, ELWFmtStAlign, ELWNotPositive, ELWEnd, ELWFmtEndAlign, |
|
107 ELWLength, ELFStart, ELFEnd, ELFNotPositive, |
|
108 ERPIInUse = 0x0050, |
|
109 EPCInUse = 0x0060, EPCFunc, |
|
110 ESECBQueued = 0x0070, |
|
111 EDSEDRequest = 0x0080, EDSEDNotErrComplete, |
|
112 ECRReqIdle = 0x0090, ECRRequest, |
|
113 ERRBStAlign = 0x00a0, ERRBStPos, ERRBNotPositive, ERRBEndAlign, ERRBEndPos, |
|
114 ERRBOverflow, ERRBCchInv, ERRBExist, |
|
115 ERWBStPos = 0x00b0, ERWBNotPositive, ERWBEndPos, ERWBOverflow, ERWBCchInv, |
|
116 EMBStPos = 0x00c0, EMBStAlign, EMBNotPositive, EMBEndPos, EMBEndAlign, |
|
117 EMBOverflow, EMBCchInvPre, EMBCchInvPost, |
|
118 EBGAStPos = 0x00d0, EBGAStAlign, EBGANotPositive, EBGAEndPos, EBGAEndAlign, |
|
119 EBGAOverflow, EBGACchInv, |
|
120 EICMNegative = 0x00e0, EICMOverflow, ECMIOverflow, |
|
121 EGCBAlign = 0x00f0, EGCBPos, EGCBCchInv, |
|
122 |
|
123 ECFSessPtrNull = 0x0100, // Code Fault - session pointer NULL |
|
124 |
|
125 EDBNotEven = 0x0110, // Not and even number of blocks in the buffer cache |
|
126 EDBCBQueued = 0x0111, // The data transfer callback is already queued |
|
127 EDBLength = 0x0112, // The length of data to transfer in data transfer callback is not positive |
|
128 EDBLengthTooBig = 0x0113, // The length of data to transfer in data transfer callback is too big |
|
129 EDBOffsetTooBig = 0x0114, // The Offset into the user data buffer is too big |
|
130 EDBCacheInvalid = 0x0115, // The cache is invalid at the end of data transfer |
|
131 EDBNotOptimal = 0x0116, // Due to Cache size DB functionality will never be utilised |
|
132 ENoDBSupport = 0x0120, // DMA request arrived but PSL does not support double buffering |
|
133 ENotDMAAligned = 0x0121, |
|
134 }; |
|
135 static void Panic(TPanic aPnc); |
|
136 |
|
137 enum TMediaRequest |
|
138 { |
|
139 EMReqRead = 0, |
|
140 EMReqWrite = 1, |
|
141 EMReqFormat = 2, |
|
142 EMReqPtnInfo, |
|
143 EMReqPswdCtrl, |
|
144 EMReqForceErase, |
|
145 EMReqUpdatePtnInfo, |
|
146 EMReqWritePasswordData, |
|
147 EMReqIdle, |
|
148 EMReqEMMCPtnInfo, |
|
149 }; |
|
150 enum TMediaReqType {EMReqTypeNormalRd,EMReqTypeNormalWr,EMReqTypeUnlockPswd,EMReqTypeChangePswd}; |
|
151 |
|
152 enum {KWtRBMFst = 0x00000001, // iWtRBM - Read First Block only |
|
153 KWtRBMLst = 0x00000002, // iWtRBM - Read Last Block only |
|
154 KWtMinFst = 0x00000004, // iWtRBM - Write First Block only |
|
155 KWtMinLst = 0x00000008, // iWtRBM - Write Last Block only |
|
156 KIPCSetup = 0x00000010, // iRdROB - IPC Setup Next Iteration |
|
157 KIPCWrite = 0x00000020}; // iRdROB - IPC Write Next Iteration |
|
158 |
|
159 private: |
|
160 // MMC device specific stuff |
|
161 TInt DoRead(); |
|
162 TInt DoWrite(); |
|
163 TInt DoFormat(); |
|
164 TInt Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo); |
|
165 |
|
166 inline DMMCStack& Stack() const; |
|
167 inline TInt CardNum() const; |
|
168 inline TMediaRequest CurrentRequest() const; |
|
169 |
|
170 TInt LaunchRead(TInt64 aStart, TUint32 aLength); |
|
171 TInt LaunchDBRead(); |
|
172 TInt LaunchPhysRead(TInt64 aStart, TUint32 aLength); |
|
173 |
|
174 TInt LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq); |
|
175 TInt LaunchFormat(TInt64 aStart, TUint32 aLength); |
|
176 |
|
177 TInt LaunchRPIUnlock(TLocalDrivePasswordData& aData); |
|
178 TInt LaunchRPIRead(); |
|
179 TInt LaunchRPIErase(); |
|
180 TInt DecodePartitionInfo(); |
|
181 TInt WritePartitionInfo(); |
|
182 TInt GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry); |
|
183 TInt CreateDefaultPartition(); |
|
184 |
|
185 |
|
186 #if defined __TEST_PAGING_MEDIA_DRIVER__ |
|
187 TInt HandleControlIORequest(); |
|
188 #endif |
|
189 |
|
190 static void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors); |
|
191 |
|
192 TInt CheckDevice(TMediaReqType aReqType); |
|
193 |
|
194 static void SessionEndCallBack(TAny* aMediaDriver); |
|
195 static void SessionEndDfc(TAny* aMediaDriver); |
|
196 void DoSessionEndDfc(); |
|
197 |
|
198 static void DataTransferCallBack(TAny* aMediaDriver); |
|
199 static void DataTransferCallBackDfc(TAny* aMediaDriver); |
|
200 |
|
201 void DoReadDataTransferCallBack(); |
|
202 void DoWriteDataTransferCallBack(); |
|
203 void DoPhysReadDataTransferCallBack(); |
|
204 void DoPhysWriteDataTransferCallBack(); |
|
205 |
|
206 TInt AdjustPhysicalFragment(TPhysAddr &physAddr, TInt &physLength); |
|
207 TInt PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength); |
|
208 void PrepareNextPhysicalFragment(); |
|
209 |
|
210 TInt EngageAndSetReadRequest(TMediaRequest aRequest); |
|
211 TInt EngageAndSetWriteRequest(TMediaRequest aRequest); |
|
212 TInt EngageAndSetRequest(TMediaRequest aRequest, TInt aCurrent); |
|
213 void CompleteRequest(TInt aReason); |
|
214 |
|
215 TInt ReadDataUntilCacheExhausted(TBool* aAllDone); |
|
216 TInt WriteDataToUser(TUint8* aBufPtr); |
|
217 TInt ReadDataFromUser(TDes8& aDes, TInt aOffset); |
|
218 TUint8* ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength); |
|
219 TUint8* ReserveWriteBlocks(TInt64 aMedStart, TInt64 aMedEnd, TUint* aRBM); |
|
220 void MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex); |
|
221 void BuildGammaArray(TInt64 aStart, TInt64 aEnd); |
|
222 void InvalidateCache(); |
|
223 void InvalidateCache(TInt64 aStart, TInt64 aEnd); |
|
224 TUint8* IdxToCchMem(TInt aIdx) const; |
|
225 TInt CchMemToIdx(TUint8* aMemP) const; |
|
226 |
|
227 TInt DoPasswordOp(); |
|
228 void PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData); |
|
229 void Reset(); |
|
230 TInt AllocateSession(); |
|
231 |
|
232 #ifdef _DEBUG_CACHE |
|
233 TBool CacheInvariant(); |
|
234 TUint8* GetCachedBlock(TInt64 aAddr); |
|
235 #endif |
|
236 private: |
|
237 DMMCStack* iStack; // controller objects |
|
238 TMMCard* iCard; |
|
239 DMMCSession* iSession; |
|
240 DMMCSocket* iSocket; |
|
241 |
|
242 TInt iCardNumber; |
|
243 |
|
244 TUint iBlkLenLog2; // cached CSD data |
|
245 TUint32 iBlkLen; |
|
246 TInt64 iBlkMsk; |
|
247 TBool iReadBlPartial; |
|
248 TUint32 iPrWtGpLen; // preferred write group size in bytes, |
|
249 TInt64 iPrWtGpMsk; |
|
250 |
|
251 TInt iReadCurrentInMilliAmps; // power management |
|
252 TInt iWriteCurrentInMilliAmps; |
|
253 |
|
254 TUint8* iMinorBuf; // MBR, CMD42, partial read |
|
255 TUint8* iCacheBuf; // cached buffer |
|
256 TUint32 iMaxBufSize; |
|
257 TInt iBlocksInBuffer; |
|
258 TInt64* iCachedBlocks; |
|
259 TInt* iGamma; // B lookup, ReserveReadBlocks() |
|
260 TUint8* iIntBuf; // start of current buffer region |
|
261 TInt iLstUsdCchEnt; // index of last used cache entry |
|
262 |
|
263 TLocDrvRequest* iCurrentReq; // Current Request |
|
264 TMediaRequest iMedReq; |
|
265 |
|
266 TInt64 iReqStart; // user-requested start region |
|
267 TInt64 iReqCur; // Currently requested start region |
|
268 TInt64 iReqEnd; // user-requested end region |
|
269 TInt64 iPhysStart; // physical region for one operation |
|
270 TInt64 iPhysEnd; // physical end point for one operation |
|
271 TInt64 iDbEnd; // Double buffer end point for one operation |
|
272 |
|
273 TUint64 iEraseUnitMsk; |
|
274 |
|
275 TUint iWtRBM; // Write - Read Before Modify Flags |
|
276 TUint iRdROB; // Read - Read Odd Blocks Flags |
|
277 |
|
278 TInt iFragOfset; |
|
279 TUint32 iIPCLen; |
|
280 TUint32 iNxtIPCLen; |
|
281 TUint32 iBufOfset; |
|
282 |
|
283 TUint iHiddenSectors; // bootup / password |
|
284 |
|
285 TMMCCallBack iSessionEndCallBack; |
|
286 TDfc iSessionEndDfc; |
|
287 |
|
288 TPartitionInfo* iPartitionInfo; |
|
289 TMMCMediaTypeEnum iMediaType; |
|
290 TMMCEraseInfo iEraseInfo; |
|
291 TBool iMbrMissing; |
|
292 TInt iMediaId; |
|
293 |
|
294 DMMCStack::TDemandPagingInfo iDemandPagingInfo; |
|
295 |
|
296 #if defined(__TEST_PAGING_MEDIA_DRIVER__) |
|
297 SMmcStats iMmcStats; |
|
298 #endif // __TEST_PAGING_MEDIA_DRIVER__ |
|
299 |
|
300 TMMCCallBack iDataTransferCallBack; // Callback registered with the MMC stack to perform double-buffering |
|
301 TDfc iDataTransferCallBackDfc; // ...and the associated DFC queue. |
|
302 |
|
303 TBool iSecondBuffer; // Specified the currently active buffer |
|
304 TBool iDoLastRMW; // ETrue if the last double-buffer transfer requires RMW modification |
|
305 TBool iDoDoubleBuffer; // ETrue if double-buffering is currently active |
|
306 TBool iDoPhysicalAddress; // ETrue if Physical Addressing is currently active |
|
307 TBool iCreateMbr; |
|
308 TBool iReadToEndOfCard; // {Read Only} ETrue if Reading to end of Card |
|
309 |
|
310 TBool iInternalSlot; |
|
311 |
|
312 DEMMCPartitionInfo* iMmcPartitionInfo; // Responsible for decoding partitions for embedded devices |
|
313 }; |
|
314 |
|
315 // ======== DPhysicalDeviceMediaMmcFlash ======== |
|
316 |
|
317 |
|
318 DPhysicalDeviceMediaMmcFlash::DPhysicalDeviceMediaMmcFlash() |
|
319 { |
|
320 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ctr")); |
|
321 |
|
322 iUnitsMask = 0x01; |
|
323 iVersion = TVersion(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion); |
|
324 } |
|
325 |
|
326 |
|
327 TInt DPhysicalDeviceMediaMmcFlash::Install() |
|
328 { |
|
329 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ins")); |
|
330 |
|
331 _LIT(KDrvNm, "Media.MmcF"); |
|
332 return SetName(&KDrvNm); |
|
333 } |
|
334 |
|
335 |
|
336 void DPhysicalDeviceMediaMmcFlash::GetCaps(TDes8& /* aDes */) const |
|
337 { |
|
338 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:cap")); |
|
339 } |
|
340 |
|
341 |
|
342 TInt DPhysicalDeviceMediaMmcFlash::Info(TInt aFunction, TAny* /*a1*/) |
|
343 // |
|
344 // Return the priority of this media driver |
|
345 // |
|
346 { |
|
347 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:info")); |
|
348 if (aFunction==EPriority) |
|
349 return KMediaDriverPriorityNormal; |
|
350 // Don't close media driver when peripheral bus powers down. This avoids the need for Caps() to power up the stack. |
|
351 if (aFunction==EMediaDriverPersistent) |
|
352 return KErrNone; |
|
353 return KErrNotSupported; |
|
354 } |
|
355 |
|
356 TInt DPhysicalDeviceMediaMmcFlash::Validate(TInt aDeviceType, const TDesC8* /*aInfo*/, const TVersion& aVer) |
|
357 { |
|
358 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:validate aDeviceType %d", aDeviceType)); |
|
359 if (!Kern::QueryVersionSupported(iVersion,aVer)) |
|
360 return KErrNotSupported; |
|
361 if (aDeviceType!=MEDIA_DEVICE_MMC) |
|
362 return KErrNotSupported; |
|
363 return KErrNone; |
|
364 } |
|
365 |
|
366 TInt DPhysicalDeviceMediaMmcFlash::Create(DBase*& aChannel, TInt aMediaId, const TDesC8* /*aInfo*/, const TVersion& aVer) |
|
367 // |
|
368 // Create an MMC Card media driver. |
|
369 // |
|
370 { |
|
371 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:crt")); |
|
372 |
|
373 if (!Kern::QueryVersionSupported(iVersion,aVer)) |
|
374 return KErrNotSupported; |
|
375 |
|
376 DMmcMediaDriverFlash* pD = new DMmcMediaDriverFlash(aMediaId); |
|
377 aChannel=pD; |
|
378 |
|
379 TInt r=KErrNoMemory; |
|
380 if (pD) |
|
381 r=pD->DoCreate(aMediaId); |
|
382 if (r==KErrNone) |
|
383 pD->OpenMediaDriverComplete(KErrNone); |
|
384 |
|
385 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:mdf")); |
|
386 return r; |
|
387 } |
|
388 |
|
389 |
|
390 // ======== DMmcMediaDriverFlash ======== |
|
391 |
|
392 |
|
393 void DMmcMediaDriverFlash::Panic(TPanic aPanic) |
|
394 { |
|
395 _LIT(KPncNm, "MEDMMC"); |
|
396 Kern::PanicCurrentThread(KPncNm, aPanic); |
|
397 } |
|
398 |
|
399 |
|
400 // ---- accessor functions ----- |
|
401 |
|
402 inline DMMCStack& DMmcMediaDriverFlash::Stack() const |
|
403 { return *static_cast<DMMCStack*>(iStack); } |
|
404 |
|
405 |
|
406 inline TInt DMmcMediaDriverFlash::CardNum() const |
|
407 { return iCardNumber; } |
|
408 |
|
409 |
|
410 inline DMmcMediaDriverFlash::TMediaRequest DMmcMediaDriverFlash::CurrentRequest() const |
|
411 { return iMedReq; } |
|
412 |
|
413 |
|
414 // Helper |
|
415 template <class T> |
|
416 inline T* KernAlloc(const TUint32 n) |
|
417 { return static_cast<T*>(Kern::Alloc(n * sizeof(T))); } |
|
418 |
|
419 // ---- ctor, open, close, dtor ---- |
|
420 |
|
421 #pragma warning( disable : 4355 ) // this used in initializer list |
|
422 DMmcMediaDriverFlash::DMmcMediaDriverFlash(TInt aMediaId) |
|
423 :DMediaDriver(aMediaId), |
|
424 iMedReq(EMReqIdle), |
|
425 iSessionEndCallBack(DMmcMediaDriverFlash::SessionEndCallBack, this), |
|
426 iSessionEndDfc(DMmcMediaDriverFlash::SessionEndDfc, this, 1), |
|
427 iMediaId(iPrimaryMedia->iNextMediaId), |
|
428 iDataTransferCallBack(DMmcMediaDriverFlash::DataTransferCallBack, this), |
|
429 iDataTransferCallBackDfc(DMmcMediaDriverFlash::DataTransferCallBackDfc, this, 1) |
|
430 { |
|
431 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:mmd")); |
|
432 // NB aMedia Id = the media ID of the primary media, iMediaId = the media ID of this media |
|
433 __KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash(), iMediaId %d, aMediaId %d\n", iMediaId, aMediaId)); |
|
434 } |
|
435 |
|
436 #pragma warning( default : 4355 ) |
|
437 TInt DMmcMediaDriverFlash::DoCreate(TInt /*aMediaId*/) |
|
438 { |
|
439 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:opn")); |
|
440 |
|
441 iSocket = ((DMMCSocket*)((DPBusPrimaryMedia*)iPrimaryMedia)->iSocket); |
|
442 if(iSocket == NULL) |
|
443 return(KErrNoMemory); |
|
444 |
|
445 iCardNumber = ((DPBusPrimaryMedia*)iPrimaryMedia)->iSlotNumber; |
|
446 |
|
447 iStack = iSocket->Stack(KStackNumber); |
|
448 iCard = iStack->CardP(CardNum()); |
|
449 |
|
450 TMMCMachineInfo machineInfo; |
|
451 Stack().MachineInfo(machineInfo); |
|
452 TInt slotFlag = iCardNumber == 0 ? TMMCMachineInfo::ESlot1Internal : TMMCMachineInfo::ESlot2Internal; |
|
453 iInternalSlot = machineInfo.iFlags & slotFlag; |
|
454 |
|
455 __KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash::DoCreate() slotNumber %d iInternalSlot %d", iCardNumber, iInternalSlot)); |
|
456 |
|
457 |
|
458 iSessionEndDfc.SetDfcQ(&iSocket->iDfcQ); |
|
459 iDataTransferCallBackDfc.SetDfcQ(&iSocket->iDfcQ); |
|
460 |
|
461 // check right type of card |
|
462 if ((iMediaType=iCard->MediaType())==EMultiMediaNotSupported) |
|
463 return(KErrNotReady); |
|
464 |
|
465 // get card characteristics |
|
466 const TCSD& csd = iCard->CSD(); |
|
467 iBlkLenLog2 = iCard->MaxReadBlLen(); |
|
468 iBlkLen = 1 << iBlkLenLog2; |
|
469 iBlkMsk = (TInt64)(iBlkLen - 1); |
|
470 |
|
471 SetTotalSizeInBytes(iCard->DeviceSize64()); |
|
472 |
|
473 // |
|
474 // High capcity cards (block addressable, MMCV4.2, SD2.0) do not support partial reads |
|
475 // ...some cards incorrectly report that they do, so ensure that we don't |
|
476 // |
|
477 iReadBlPartial = iCard->IsHighCapacity() ? EFalse : csd.ReadBlPartial(); |
|
478 |
|
479 // allocate and initialize session object |
|
480 TInt r = AllocateSession(); |
|
481 if (r!= KErrNone) |
|
482 return r; |
|
483 |
|
484 // get buffer memory from EPBUS |
|
485 TUint8* buf; |
|
486 TInt bufLen; |
|
487 TInt minorBufLen; |
|
488 Stack().BufferInfo(buf, bufLen, minorBufLen); |
|
489 |
|
490 iMinorBuf = buf; |
|
491 |
|
492 // cache buffer can use rest of blocks in buffer. Does not have to be power of 2. |
|
493 iCacheBuf = iMinorBuf + minorBufLen; |
|
494 |
|
495 // We need to devide up the buffer space between the media drivers. |
|
496 // The number of buffer sub-areas = number of physical card slots * number of media |
|
497 bufLen-= minorBufLen; |
|
498 DPBusPrimaryMedia* primaryMedia = (DPBusPrimaryMedia*) iPrimaryMedia; |
|
499 TInt physicalCardSlots = iStack->iMaxCardsInStack; |
|
500 TInt numMedia = primaryMedia->iLastMediaId - primaryMedia->iMediaId + 1; |
|
501 TInt totalNumMedia = numMedia * physicalCardSlots; |
|
502 |
|
503 TInt mediaIndex = iMediaId - primaryMedia->iMediaId; |
|
504 TInt bufIndex = (iCardNumber * numMedia) + mediaIndex; |
|
505 |
|
506 __KTRACE_OPT(KPBUSDRV, Kern::Printf("physicalCardSlots %d, iCardNumber %d\n", physicalCardSlots, iCardNumber)); |
|
507 __KTRACE_OPT(KPBUSDRV, Kern::Printf("iMediaId %d numMedia %d, mediaIndex %d, totalNumMedia %d, bufIndex %d\n", |
|
508 iMediaId, numMedia, mediaIndex, totalNumMedia, bufIndex)); |
|
509 |
|
510 __KTRACE_OPT(KPBUSDRV, Kern::Printf("bufLen1 %08X iCacheBuf1 %08X", bufLen, iCacheBuf)); |
|
511 bufLen/= totalNumMedia; |
|
512 iCacheBuf+= bufIndex * bufLen; |
|
513 __KTRACE_OPT(KPBUSDRV, Kern::Printf("bufLen2 %08X iCacheBuf2 %08X", bufLen, iCacheBuf)); |
|
514 |
|
515 iBlocksInBuffer = bufLen >> iBlkLenLog2; // may lose partial block |
|
516 if(iSocket->SupportsDoubleBuffering()) |
|
517 { |
|
518 // Ensure that there's always an even number of buffered blocks when double-buffering |
|
519 iBlocksInBuffer &= ~1; |
|
520 __ASSERT_DEBUG(iBlocksInBuffer >= 2, Panic(EDBNotEven)); |
|
521 #if defined(_DEBUG) |
|
522 /** |
|
523 * If Double-Buffering is enabled then the cache should not be greater than the maximum addressable range of the DMA controller, |
|
524 * otherwise Double buffering will never be utilised because all transfers will fit into the cache. |
|
525 */ |
|
526 const TUint32 maxDbBlocks = iSocket->MaxDataTransferLength() >> iBlkLenLog2; |
|
527 __ASSERT_DEBUG(iBlocksInBuffer <= (TInt)maxDbBlocks, Panic(EDBNotOptimal)); |
|
528 #endif |
|
529 } |
|
530 |
|
531 iMaxBufSize = iBlocksInBuffer << iBlkLenLog2; |
|
532 |
|
533 iPrWtGpLen = iCard->PreferredWriteGroupLength(); |
|
534 |
|
535 // check the preferred write group length is a power of two |
|
536 if(iPrWtGpLen == 0 || (iPrWtGpLen & (~iPrWtGpLen + 1)) != iPrWtGpLen) |
|
537 return(KErrNotReady); |
|
538 |
|
539 __KTRACE_OPT(KPBUSDRV, Kern::Printf("iMaxBufSize %d iPrWtGpLen %d\n", iMaxBufSize, iPrWtGpLen)); |
|
540 // ensure the preferred write group length is as large as possible |
|
541 // so we can write to more than one write group at once |
|
542 while (iPrWtGpLen < (TUint32) iMaxBufSize) |
|
543 iPrWtGpLen <<= 1; |
|
544 |
|
545 // ensure preferred write group length is no greater than internal cache buffer |
|
546 while (iPrWtGpLen > (TUint32) iMaxBufSize) |
|
547 iPrWtGpLen >>= 1; |
|
548 iPrWtGpMsk = TInt64(iPrWtGpLen - 1); |
|
549 |
|
550 __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPrWtGpLen #2 %d\n", iPrWtGpLen)); |
|
551 |
|
552 // allocate index for cached blocks |
|
553 iCachedBlocks = KernAlloc<TInt64>(iBlocksInBuffer); |
|
554 if (iCachedBlocks == 0) |
|
555 return(KErrNoMemory); |
|
556 |
|
557 InvalidateCache(); |
|
558 iLstUsdCchEnt = iBlocksInBuffer - 1; // use entry 0 first |
|
559 |
|
560 // allocate read lookup index |
|
561 iGamma = KernAlloc<TInt>(iBlocksInBuffer); |
|
562 if (iGamma == 0) |
|
563 return(KErrNoMemory); |
|
564 |
|
565 // get current requirements |
|
566 iReadCurrentInMilliAmps = csd.MaxReadCurrentInMilliamps(); |
|
567 iWriteCurrentInMilliAmps = csd.MaxWriteCurrentInMilliamps(); |
|
568 |
|
569 // get preferred erase information for format operations |
|
570 const TInt err = iCard->GetEraseInfo(iEraseInfo); |
|
571 if(err != KErrNone) |
|
572 return(err); |
|
573 |
|
574 iEraseUnitMsk = TInt64(iEraseInfo.iPreferredEraseUnitSize) - 1; |
|
575 |
|
576 // Retrieve the demand paging info from the PSL of the stack |
|
577 Stack().DemandPagingInfo(iDemandPagingInfo); |
|
578 |
|
579 // if a password has been supplied then it is sent when the partition info is read |
|
580 |
|
581 // |
|
582 // If this is an internal slot, then use the eMMC partition function |
|
583 // |
|
584 if(iInternalSlot) |
|
585 { |
|
586 iMmcPartitionInfo = CreateEmmcPartitionInfo(); |
|
587 if(iMmcPartitionInfo == NULL) |
|
588 return KErrNoMemory; |
|
589 |
|
590 TInt err = iMmcPartitionInfo->Initialise(this); |
|
591 if(err != KErrNone) |
|
592 return err; |
|
593 } |
|
594 |
|
595 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:opn")); |
|
596 |
|
597 return(KErrNone); |
|
598 } |
|
599 |
|
600 void DMmcMediaDriverFlash::Close() |
|
601 // |
|
602 // Close the media driver - also called on media change |
|
603 // |
|
604 { |
|
605 __KTRACE_OPT(KPBUSDRV,Kern::Printf("=mmd:cls")); |
|
606 |
|
607 EndInCritical(); |
|
608 iSessionEndDfc.Cancel(); |
|
609 iDataTransferCallBackDfc.Cancel(); |
|
610 CompleteRequest(KErrNotReady); |
|
611 DMediaDriver::Close(); |
|
612 } |
|
613 |
|
614 |
|
615 DMmcMediaDriverFlash::~DMmcMediaDriverFlash() |
|
616 { |
|
617 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dtr")); |
|
618 |
|
619 iSessionEndDfc.Cancel(); |
|
620 iDataTransferCallBackDfc.Cancel(); |
|
621 |
|
622 delete iSession; |
|
623 Kern::Free(iCachedBlocks); |
|
624 Kern::Free(iGamma); |
|
625 |
|
626 delete iMmcPartitionInfo; |
|
627 |
|
628 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dtr")); |
|
629 } |
|
630 |
|
631 |
|
632 TInt DMmcMediaDriverFlash::AllocateSession() |
|
633 { |
|
634 // already allocated ? |
|
635 if (iSession != NULL) |
|
636 return KErrNone; |
|
637 |
|
638 iSession = iStack->AllocSession(iSessionEndCallBack); |
|
639 if (iSession == NULL) |
|
640 return KErrNoMemory; |
|
641 |
|
642 iSession->SetStack(iStack); |
|
643 iSession->SetCard(iCard); |
|
644 iSession->SetDataTransferCallback(iDataTransferCallBack); |
|
645 |
|
646 return KErrNone; |
|
647 } |
|
648 |
|
649 // ---- media access ---- |
|
650 |
|
651 TInt DMmcMediaDriverFlash::DoRead() |
|
652 // |
|
653 // set up iReqStart, iReqEnd and iReqCur and launch first read. Subsequent reads |
|
654 // will be launched from the callback DFC. |
|
655 // |
|
656 { |
|
657 TInt r = CheckDevice(EMReqTypeNormalRd); |
|
658 if (r != KErrNone) return r; |
|
659 |
|
660 const TInt64 pos(iCurrentReq->Pos()); |
|
661 TUint32 length(I64LOW(iCurrentReq->Length())); |
|
662 |
|
663 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dr:0x%lx,0x%x", pos, length)); |
|
664 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDRInUse)); |
|
665 __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDRStart)); |
|
666 __ASSERT_DEBUG(iCurrentReq->Length() >= 0, Panic(EDRNotPositive)); |
|
667 __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDREnd)); |
|
668 |
|
669 if(length > 0) |
|
670 { |
|
671 iReqCur = iReqStart = pos; |
|
672 iReqEnd = iReqStart + length; |
|
673 |
|
674 TBool allDone(EFalse); |
|
675 if ( ((r = ReadDataUntilCacheExhausted(&allDone)) == KErrNone) && !allDone) |
|
676 { |
|
677 iMedReq = EMReqRead; |
|
678 iPhysStart = iReqCur & ~iBlkMsk; |
|
679 __ASSERT_DEBUG(I64HIGH(iPhysStart >> KMMCardHighCapBlockSizeLog2) == 0, Panic(ELRStart)); |
|
680 |
|
681 iReadToEndOfCard = ( iReqEnd >= TotalSizeInBytes() ); |
|
682 // Re-calculate length as some data may have been recovered from cache |
|
683 length = I64LOW(iReqEnd - iReqCur); |
|
684 |
|
685 if (iCurrentReq->IsPhysicalAddress() && !iReadToEndOfCard && (length >= iBlkLen) ) |
|
686 r = LaunchPhysRead(iReqCur, length); |
|
687 else if ( (iReqEnd - iPhysStart) > iMaxBufSize && iSocket->SupportsDoubleBuffering() && !iReadToEndOfCard) |
|
688 r = LaunchDBRead(); |
|
689 else |
|
690 r = LaunchRead(iReqCur, length); |
|
691 |
|
692 if (r == KErrNone) return r; |
|
693 } |
|
694 } |
|
695 else |
|
696 { |
|
697 #if defined(__DEMAND_PAGING__) && !defined(__WINS__) |
|
698 if (DMediaPagingDevice::PageInRequest(*iCurrentReq)) |
|
699 { |
|
700 r = iCurrentReq->WriteToPageHandler(NULL, 0, 0); |
|
701 } |
|
702 else |
|
703 #endif // __DEMAND_PAGING__ |
|
704 { |
|
705 TPtrC8 zeroDes(NULL, 0); |
|
706 r = iCurrentReq->WriteRemote(&zeroDes,0); |
|
707 } |
|
708 } |
|
709 |
|
710 // error occurred or read all from cache so complete immediately |
|
711 if(r == KErrNone) |
|
712 r = KErrCompletion; |
|
713 |
|
714 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dr:%d", r)); |
|
715 |
|
716 return r; |
|
717 } |
|
718 |
|
719 |
|
720 TInt DMmcMediaDriverFlash::LaunchRead(TInt64 aStart, TUint32 aLength) |
|
721 // |
|
722 // starts reads from DoRead() and the session end DFC. This function does not maintain the |
|
723 // iReq* instance variables. It sets iPhysStart and iPhysEnd to the region that was actually |
|
724 // read into iIntBuf. iIntBuf can be set to a cached entry or to the minor buffer. It is |
|
725 // assumed that before this function is called that ReadDataUntilCacheExhausted() has been used. |
|
726 // |
|
727 { |
|
728 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lr:0x%lx,0x%x", aStart, aLength)); |
|
729 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELRStart)); |
|
730 __ASSERT_DEBUG(aLength > 0, Panic(ELRNotPositive)); |
|
731 __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELREnd)); |
|
732 __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ELRCached)); |
|
733 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
734 |
|
735 iDoPhysicalAddress = EFalse; |
|
736 iDoDoubleBuffer = EFalse; |
|
737 iSecondBuffer = EFalse; |
|
738 |
|
739 // |
|
740 // if this read goes up to the end of the card then use only |
|
741 // single sector reads to avoid CMD12 timing problems |
|
742 // |
|
743 const TUint32 bufSize(iReadToEndOfCard ? iBlkLen : iMaxBufSize); |
|
744 |
|
745 iPhysEnd = (UMin(iReqEnd, iPhysStart + bufSize) + iBlkMsk) & ~iBlkMsk; |
|
746 |
|
747 TUint32 physLen(I64LOW(iPhysEnd - iPhysStart)); |
|
748 |
|
749 __ASSERT_DEBUG(I64HIGH(iPhysEnd - iPhysStart) == 0, Panic(ELREnd)); |
|
750 |
|
751 // partial reads must be within a single physical block |
|
752 if (iReadBlPartial && physLen == iBlkLen && aLength <= (iBlkLen >> 1)) |
|
753 { |
|
754 // |
|
755 // Note : Partial reads are not supported for large block devices |
|
756 // (MMCV4.2 and SD2.0 high capacity cards) |
|
757 // |
|
758 __ASSERT_DEBUG(I64HIGH(aStart) == 0, Panic(ELRStart)); |
|
759 __ASSERT_DEBUG(I64HIGH(aStart + aLength) == 0, Panic(ELREnd)); |
|
760 |
|
761 iIntBuf = iMinorBuf; |
|
762 Stack().AdjustPartialRead(iCard, I64LOW(aStart), I64LOW(aStart + aLength), (TUint32*)&iPhysStart, (TUint32*)&iPhysEnd); |
|
763 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, physLen >> KMMCardHighCapBlockSizeLog2); |
|
764 } |
|
765 else |
|
766 { |
|
767 iIntBuf = ReserveReadBlocks(iPhysStart, iPhysEnd, &physLen); |
|
768 |
|
769 // EPBUSM automatically uses CMD17 instead of CMD18 for single block reads |
|
770 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, physLen >> KMMCardHighCapBlockSizeLog2); |
|
771 |
|
772 // Update Physical end point as less may have been required due to additional blocks found in cache during ReserveReadBlocks |
|
773 iPhysEnd = iPhysStart + physLen; |
|
774 } |
|
775 |
|
776 TInt r = EngageAndSetReadRequest(EMReqRead); |
|
777 |
|
778 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lr:%d", r)); |
|
779 return r; |
|
780 } |
|
781 |
|
782 TInt DMmcMediaDriverFlash::LaunchDBRead() |
|
783 // |
|
784 // starts reads from DoRead() and the session end DFC. This function does not maintain the |
|
785 // iReq* instance variables. It sets iPhysStart and iPhysEnd to the region that was actually |
|
786 // read into iIntBuf. iIntBuf can be set to a cached entry or to the minor buffer. It is |
|
787 // assumed that before this function is called that ReadDataUntilCacheExhausted() has been used. |
|
788 // |
|
789 { |
|
790 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:ldbr:0x%lx,0x%x", iReqCur, I64LOW(iReqEnd - iReqCur))); |
|
791 __ASSERT_DEBUG(TotalSizeInBytes() > iReqCur, Panic(ELRStart)); |
|
792 __ASSERT_DEBUG(I64LOW(iReqEnd - iReqCur) > 0, Panic(ELRNotPositive)); |
|
793 __ASSERT_DEBUG(TotalSizeInBytes() >= iReqEnd, Panic(ELREnd)); |
|
794 __ASSERT_CACHE(GetCachedBlock(iReqCur & ~iBlkMsk) == 0, Panic(ELRCached)); |
|
795 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
796 |
|
797 iDoDoubleBuffer = ETrue; |
|
798 iDoPhysicalAddress = EFalse; |
|
799 |
|
800 iDbEnd = iReqEnd; |
|
801 const TUint32 maxDbLength = iSocket->MaxDataTransferLength(); |
|
802 |
|
803 if(maxDbLength) |
|
804 { |
|
805 // |
|
806 // If the PSL specifies a limit on the maximum size of a data transfer, then truncate the request... |
|
807 // |
|
808 iDbEnd = UMin(iDbEnd, iPhysStart + maxDbLength); |
|
809 } |
|
810 |
|
811 iDbEnd = (iDbEnd + iBlkMsk) & ~iBlkMsk; |
|
812 |
|
813 const TUint32 doubleBufferSize = iMaxBufSize >> 1; |
|
814 iPhysEnd = (iReqCur + doubleBufferSize) & ~iBlkMsk; // The end of the first double-buffered transfer |
|
815 |
|
816 // |
|
817 // If we're double-buffering, then the entire cache will be re-used |
|
818 // continuously. Rather than continually reserve blocks during each |
|
819 // transfer we calculate the blocks that will be present after all |
|
820 // transfers have completed. |
|
821 // @see DoSessionEndDfc() |
|
822 // |
|
823 InvalidateCache(); |
|
824 iIntBuf = iCacheBuf; |
|
825 |
|
826 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW(iDbEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2); |
|
827 |
|
828 iSession->EnableDoubleBuffering(doubleBufferSize >> KDiskSectorShift); |
|
829 |
|
830 // ...and switch to the 'second' buffer, which will be populated in the |
|
831 // data transfer callback in parallel with hardware transfer of the first. |
|
832 iSecondBuffer = ETrue; |
|
833 |
|
834 TInt r = EngageAndSetReadRequest(EMReqRead); |
|
835 |
|
836 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:ldbr:%d", r)); |
|
837 |
|
838 return r; |
|
839 } |
|
840 |
|
841 |
|
842 TInt DMmcMediaDriverFlash::LaunchPhysRead(TInt64 aStart, TUint32 aLength) |
|
843 // |
|
844 // This function does not maintain the iReq* instance variables. |
|
845 // It is assumed that before this function is called that |
|
846 // ReadDataUntilCacheExhausted() has been used. |
|
847 // |
|
848 { |
|
849 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:physr:0x%lx,0x%x", aStart, aLength)); |
|
850 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELRStart)); |
|
851 __ASSERT_DEBUG(aLength > 0, Panic(ELRNotPositive)); |
|
852 __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELREnd)); |
|
853 __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ELRCached)); |
|
854 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
855 |
|
856 TInt r(KErrNone); |
|
857 |
|
858 iDoPhysicalAddress = ETrue; |
|
859 iDoDoubleBuffer = EFalse; |
|
860 |
|
861 // Local Media Subsystem ensures DMA Addressable range not exceeded. |
|
862 // @see LocDrv::RegisterDmaDevice() |
|
863 iPhysEnd = (iReqEnd + iBlkMsk) & ~iBlkMsk; |
|
864 |
|
865 iRdROB = 0; |
|
866 iFragOfset = iIPCLen = iNxtIPCLen = iBufOfset = 0; |
|
867 |
|
868 // Determine if start/end are block aligned |
|
869 // physical memory can only read the exact amount, not more! |
|
870 const TBool firstPartial( (aStart & iBlkMsk) != 0); |
|
871 |
|
872 TPhysAddr physAddr(0); |
|
873 TInt physLength(0); |
|
874 TUint32 physLen(I64LOW(iPhysEnd - iPhysStart)); |
|
875 |
|
876 if (firstPartial) |
|
877 { |
|
878 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:physr:FirstPartial")); |
|
879 // first index does not start on block boundary |
|
880 // iIntBuf linear address is used for IPC within DoReadDataTransferCallBack() |
|
881 iRdROB |= KIPCWrite; |
|
882 |
|
883 iIntBuf = ReserveReadBlocks(iPhysStart, iPhysStart+iBlkLen,(TUint32*)&physLength); |
|
884 #if !defined(__WINS__) |
|
885 physAddr = Epoc::LinearToPhysical((TLinAddr)iIntBuf); |
|
886 #else |
|
887 physAddr = (TPhysAddr)iIntBuf; |
|
888 #endif |
|
889 // Set SecondBuffer flag to indicate IPC cannot be done on next callback |
|
890 iSecondBuffer = ETrue; |
|
891 iBufOfset = I64LOW(iReqStart - iPhysStart); |
|
892 //iReqCur already set in DoRead; |
|
893 iFragOfset = iNxtIPCLen = physLength - iBufOfset; |
|
894 } |
|
895 else |
|
896 { |
|
897 // Determine offset from start due to data possibly recovered from local cache |
|
898 iFragOfset = I64LOW(aStart - iReqStart); |
|
899 r = PrepareFirstPhysicalFragment(physAddr, physLength, aLength); |
|
900 |
|
901 // No use for secondBuffer yet... |
|
902 iSecondBuffer = EFalse; |
|
903 } |
|
904 |
|
905 if(r == KErrNone) |
|
906 { |
|
907 iDbEnd = iPhysEnd; |
|
908 iPhysEnd = iPhysStart + physLength; |
|
909 |
|
910 if ((TUint32)physLength > physLen) physLength = physLen; // more memory in chunk than required |
|
911 |
|
912 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), (TUint8*)physAddr, physLen >> KMMCardHighCapBlockSizeLog2); |
|
913 |
|
914 iSession->Command().iFlags|= KMMCCmdFlagPhysAddr; |
|
915 iSession->EnableDoubleBuffering(physLength >> KDiskSectorShift); |
|
916 |
|
917 r = EngageAndSetReadRequest(EMReqRead); |
|
918 } |
|
919 |
|
920 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lphysr:%d", r)); |
|
921 |
|
922 return r; |
|
923 } |
|
924 |
|
925 |
|
926 TInt DMmcMediaDriverFlash::DoWrite() |
|
927 // |
|
928 // set up iReqStart, iReqEnd, and iReqCur, and launch first write. Any subsequent |
|
929 // writes are launched from the session end DFC. LaunchWrite() handles pre-reading |
|
930 // any sectors that are only partially modified. |
|
931 // |
|
932 { |
|
933 const TInt64 pos = iCurrentReq->Pos(); |
|
934 const TUint32 length = I64LOW(iCurrentReq->Length()); |
|
935 |
|
936 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dw:0x%lx,0x%x", pos, length)); |
|
937 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDWInUse)); |
|
938 __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDWStart)); |
|
939 __ASSERT_DEBUG(length > 0, Panic(EDWNotPositive)); |
|
940 __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDWEnd)); |
|
941 |
|
942 iReqCur = iReqStart = pos; |
|
943 iReqEnd = iReqStart + length; |
|
944 |
|
945 // iWtRBM is zero on construction because CBase-derived, and cleared at end |
|
946 // of successful writes. If a write does not complete successfully, it may |
|
947 // be left in non-zero state. |
|
948 iWtRBM = 0; |
|
949 |
|
950 iSecondBuffer = EFalse; |
|
951 iDoLastRMW = EFalse; |
|
952 iDoDoubleBuffer= EFalse; |
|
953 iDoPhysicalAddress = EFalse; |
|
954 |
|
955 const TInt r = LaunchWrite(iReqStart, length, EMReqWrite); |
|
956 |
|
957 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dw:%d", r)); |
|
958 |
|
959 return r; |
|
960 } |
|
961 |
|
962 |
|
963 TInt DMmcMediaDriverFlash::DoFormat() |
|
964 { |
|
965 const TInt64 pos = iCurrentReq->Pos(); |
|
966 const TUint32 length = I64LOW(iCurrentReq->Length()); |
|
967 |
|
968 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:df:0x%lx,0x%x", pos, length)); |
|
969 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDFInUse)); |
|
970 __ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDFStart)); |
|
971 __ASSERT_DEBUG(length > 0, Panic(EDFNotPositive)); |
|
972 __ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDFEnd)); |
|
973 |
|
974 iReqCur = iReqStart = pos & ~iBlkMsk; |
|
975 iReqEnd = (iReqStart + length + iBlkMsk) & ~iBlkMsk; |
|
976 |
|
977 // the cache isn't maintained during a format operation to avoid redundantly |
|
978 // writing 0xff to memory (the blocks won't be re-used.) |
|
979 InvalidateCache(); |
|
980 |
|
981 // create an MBR after the first format step (or second if misaligned) |
|
982 |
|
983 if (iInternalSlot) |
|
984 { |
|
985 iCreateMbr = EFalse; |
|
986 } |
|
987 else |
|
988 { |
|
989 if (iReqStart == (TInt64(iHiddenSectors) << KDiskSectorShift) && CreateMBRAfterFormat(iCard)) |
|
990 iCreateMbr = ETrue; |
|
991 } |
|
992 |
|
993 const TInt r = LaunchFormat(iReqStart, I64LOW(iReqEnd - iReqStart)); |
|
994 |
|
995 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:df:%d", r)); |
|
996 |
|
997 return r; |
|
998 } |
|
999 |
|
1000 |
|
1001 TInt DMmcMediaDriverFlash::LaunchFormat(TInt64 aStart, TUint32 aLength) |
|
1002 // |
|
1003 // starts writes from DoWrite(), DoFormat() and the session end DFC. This function does not |
|
1004 // maintain the iReq* instance variables. It sets iIntBuf, iPhysStart and iPhysEnd. |
|
1005 // |
|
1006 { |
|
1007 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lf:0x%lx,0x%x", aStart, aLength)); |
|
1008 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELFStart)); |
|
1009 __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(ELWFmtStAlign)); |
|
1010 __ASSERT_DEBUG(aLength > 0, Panic(ELFNotPositive)); |
|
1011 __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELFEnd)); |
|
1012 __ASSERT_DEBUG((aLength & iBlkMsk) == 0, Panic(ELWFmtEndAlign)); |
|
1013 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
1014 |
|
1015 TInt r; |
|
1016 |
|
1017 if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone) |
|
1018 { |
|
1019 iPhysStart = aStart & ~iBlkMsk; |
|
1020 |
|
1021 // formats are always block-aligned, and the buffer is initialized to 0xff |
|
1022 // Check whether erase commands are supported by this card |
|
1023 if (iCard->CSD().CCC() & KMMCCmdClassErase) |
|
1024 { |
|
1025 // Determine the erase end point for the next command. We don't erase past the preferred erase unit |
|
1026 // size. Therefore, check which is lower, the preferred erase unit size or the end of the requested range. |
|
1027 TInt64 prefEraseUnitEnd = (iPhysStart + iEraseInfo.iPreferredEraseUnitSize) & ~iEraseUnitMsk; |
|
1028 iPhysEnd = UMin(prefEraseUnitEnd, aStart + aLength); |
|
1029 |
|
1030 const TUint32 minEraseSectorSize=iEraseInfo.iMinEraseSectorSize; |
|
1031 const TInt64 minEraseSecMsk = TInt64(minEraseSectorSize-1); |
|
1032 |
|
1033 // If erase start point doesn't lie on a min. erase unit boundary, then truncate the erase endpoint to |
|
1034 // the next min. erase unit boundary (assuming requested range allows this) |
|
1035 if ((iPhysStart & minEraseSecMsk)!=0) |
|
1036 { |
|
1037 prefEraseUnitEnd=(iPhysStart+minEraseSectorSize) & ~minEraseSecMsk; |
|
1038 iPhysEnd=UMin(prefEraseUnitEnd,iPhysEnd); |
|
1039 } |
|
1040 |
|
1041 // Otherwise, if calculated erase end point doesn't lie on a min. erase unit boundary, but is at least one |
|
1042 // min. erase unit beyond the erase start point then move erase endpoint back to last min. erase unit boundary |
|
1043 else if ((iPhysEnd & minEraseSecMsk)!=0 && (iPhysEnd & ~minEraseSecMsk)>iPhysStart) |
|
1044 { |
|
1045 iPhysEnd&=(~minEraseSecMsk); |
|
1046 } |
|
1047 |
|
1048 // Now, if the erase start/end points are aligned to a min. erase unit boundary, we can use an erase cmd. |
|
1049 if ((iPhysStart & minEraseSecMsk) == 0 && (iPhysEnd & minEraseSecMsk) == 0) |
|
1050 { |
|
1051 // Aligned erase |
|
1052 // Check that erase commands are supported prior to issuing an erase command |
|
1053 if(iEraseInfo.EraseGroupCmdsSupported()) |
|
1054 { |
|
1055 iSession->SetupCIMEraseMGroup(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), |
|
1056 I64LOW((iPhysEnd-iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD35/36/38 (Erase Group) |
|
1057 } |
|
1058 else |
|
1059 { |
|
1060 iSession->SetupCIMEraseMSector(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), |
|
1061 I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD32/33/38 (Erase Sector) |
|
1062 } |
|
1063 } |
|
1064 else |
|
1065 { |
|
1066 // Misaligned erase - use multi-block write. However, first - check write length doesn't exceed buffer size. |
|
1067 if ((iPhysEnd-iPhysStart)>(TUint32)iMaxBufSize) |
|
1068 { |
|
1069 iPhysEnd=(iPhysStart+iMaxBufSize); |
|
1070 } |
|
1071 |
|
1072 __ASSERT_DEBUG((iPhysEnd - iPhysStart) > 0, Panic(ELWLength)); |
|
1073 const TUint32 writeLen = I64LOW(iPhysEnd - iPhysStart); |
|
1074 memset (iCacheBuf, 0x00, writeLen); |
|
1075 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2); |
|
1076 } |
|
1077 } |
|
1078 else |
|
1079 { |
|
1080 // Write to end of current write group, or end of request range, whichever is lower |
|
1081 const TInt64 prefEraseUnitEnd = (iPhysStart + iPrWtGpLen) & ~iPrWtGpMsk; |
|
1082 iPhysEnd = Min(prefEraseUnitEnd, aStart + aLength); |
|
1083 |
|
1084 __ASSERT_DEBUG((iPhysEnd - iPhysStart) > 0, Panic(ELWLength)); |
|
1085 const TUint32 writeLen = I64LOW(iPhysEnd - iPhysStart); |
|
1086 memset (iCacheBuf, 0x00, writeLen); |
|
1087 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2); |
|
1088 } |
|
1089 |
|
1090 r = EngageAndSetWriteRequest(EMReqFormat); |
|
1091 } |
|
1092 return r; |
|
1093 } |
|
1094 |
|
1095 |
|
1096 |
|
1097 TInt DMmcMediaDriverFlash::LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq) |
|
1098 // |
|
1099 // starts writes from DoWrite(), DoFormat() and the session end DFC. This function does not |
|
1100 // maintain the iReq* instance variables. It sets iIntBuf, iPhysStart and iPhysEnd. |
|
1101 // |
|
1102 { |
|
1103 __KTRACE_OPT(KPBUSDRV, Kern::Printf("\n>mmd:lw:0x%lx,%d,%d", aStart, aLength, aMedReq)); |
|
1104 __ASSERT_DEBUG(aMedReq == EMReqWrite || aMedReq == EMReqFormat, Panic(ELWRequest)); |
|
1105 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELWStart)); |
|
1106 __ASSERT_DEBUG(!(aMedReq == EMReqFormat) || (aStart & iBlkMsk) == 0, Panic(ELWFmtStAlign)); |
|
1107 __ASSERT_DEBUG(aLength > 0, Panic(ELWNotPositive)); |
|
1108 __ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELWEnd)); |
|
1109 __ASSERT_DEBUG(!(aMedReq == EMReqFormat) || (aLength & iBlkMsk) == 0, Panic(ELWFmtEndAlign)); |
|
1110 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
1111 |
|
1112 TInt r; |
|
1113 |
|
1114 if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone) |
|
1115 { |
|
1116 iPhysStart = aStart & ~iBlkMsk; |
|
1117 |
|
1118 // PSL MUST support double-buffering for DMA requests |
|
1119 // first write, or have just completed previous write |
|
1120 if (iWtRBM == 0) |
|
1121 { |
|
1122 if(iDoDoubleBuffer == EFalse) |
|
1123 { |
|
1124 // |
|
1125 // Can we use double-buffering for this request? |
|
1126 // |
|
1127 // - Only if PSL supports double buffering and the request length |
|
1128 // is greater than the maximum PSL buffer size. |
|
1129 // |
|
1130 iDoPhysicalAddress = iCurrentReq->IsPhysicalAddress(); |
|
1131 |
|
1132 const TInt64 medEnd = aStart + aLength; |
|
1133 |
|
1134 TInt64 maxPslEnd = medEnd; |
|
1135 const TUint32 maxDbLength = iSocket->MaxDataTransferLength(); |
|
1136 |
|
1137 if(maxDbLength) |
|
1138 { |
|
1139 // |
|
1140 // If the PSL specifies a limit on the maximum size of a data transfer, then truncate the request... |
|
1141 // |
|
1142 maxPslEnd = UMin(medEnd, iPhysStart + maxDbLength); |
|
1143 } |
|
1144 |
|
1145 iPhysEnd = (maxPslEnd + iBlkMsk) & ~iBlkMsk; |
|
1146 |
|
1147 if (iDoPhysicalAddress) |
|
1148 { |
|
1149 iDoDoubleBuffer = EFalse; |
|
1150 iIntBuf = ReserveWriteBlocks(aStart, medEnd, &iWtRBM); |
|
1151 iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk; |
|
1152 } |
|
1153 |
|
1154 if (!iDoPhysicalAddress) |
|
1155 { |
|
1156 iDoDoubleBuffer = iSocket->SupportsDoubleBuffering() && ((iPhysEnd - iPhysStart) > iMaxBufSize); |
|
1157 if(iDoDoubleBuffer) |
|
1158 { |
|
1159 // |
|
1160 // Conditions for double-buffering are met. Set up the size of the first |
|
1161 // transfer to half the size of the block cache. |
|
1162 // |
|
1163 // Note that we don't bother to align to write groups here, as the entire |
|
1164 // request will be processed under one multi-block command so there's no |
|
1165 // danger of forcing the card into RMW cycles as would be the case when |
|
1166 // issuing multiple misaligned commands. |
|
1167 // |
|
1168 iDbEnd = maxPslEnd; // The end of the complete double-buffered transfer |
|
1169 iPhysEnd = (iPhysStart + (iMaxBufSize >> 1) + iBlkMsk) &~ iBlkMsk; // The end of the first double-buffered transfer |
|
1170 __ASSERT_DEBUG(iPhysEnd - iPhysStart <= (iMaxBufSize >> 1), Panic(ELWLength)); |
|
1171 |
|
1172 // |
|
1173 // Now reserve write blocks from the buffer cache. When double-buffering, |
|
1174 // write blocks are only really reserved during the last transfer to avoid |
|
1175 // continuously updating the cache indexes. Since the block cache is |
|
1176 // continuously recycled, the following call shall invalidate the cache |
|
1177 // and inform us as to whether we need to perform an RMW operation for |
|
1178 // the first and last blocks prior to initiating data transfer. |
|
1179 // |
|
1180 iIntBuf = ReserveWriteBlocks(aStart, iDbEnd, &iWtRBM); |
|
1181 } |
|
1182 else |
|
1183 { |
|
1184 // |
|
1185 // reserve buffers to end of first write group, or end of request range, |
|
1186 // whichever is lower. Note that if the range already exists in the buffer, |
|
1187 // e.g. because of a previous RBM, the same range will be returned. This |
|
1188 // means that iWtRBM can be set to zero in the callback DFC, and this code |
|
1189 // will retrieve the reserved range. |
|
1190 // |
|
1191 const TInt64 wtGpEnd = (iPhysStart + iPrWtGpLen) & ~iPrWtGpMsk; |
|
1192 const TInt64 medEnd = UMin(wtGpEnd, aStart + aLength); |
|
1193 iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk; |
|
1194 iIntBuf = ReserveWriteBlocks(aStart, medEnd, &iWtRBM); |
|
1195 } |
|
1196 } //if (!iDoPhysicalAddress) |
|
1197 } //if(iDoDoubleBuffer == EFalse) |
|
1198 } //if (iWtRBM == 0) |
|
1199 |
|
1200 if (iWtRBM & KWtRBMFst) |
|
1201 { |
|
1202 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw: read-before-modify required on first block")); |
|
1203 if (iDoPhysicalAddress) |
|
1204 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iMinorBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2); |
|
1205 else |
|
1206 iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2); |
|
1207 return EngageAndSetReadRequest(aMedReq); |
|
1208 } |
|
1209 |
|
1210 else if (iWtRBM & KWtRBMLst) |
|
1211 { |
|
1212 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw: read-before-modify required on last block")); |
|
1213 if(iDoDoubleBuffer || iDoPhysicalAddress) |
|
1214 { |
|
1215 // |
|
1216 // When double-buffering, the result of the RMW-read operation shall be stored |
|
1217 // in the minor buffer, otherwise the data would be overwritten before the last |
|
1218 // data transfer takes place. |
|
1219 // |
|
1220 const TInt64 lastBlock = (aStart + aLength) & ~iBlkMsk; // start posn in media to read from (we know aStart + aLength isn't block aligned due to KWtRBMLst flag) |
|
1221 if (iDoDoubleBuffer) |
|
1222 iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iMinorBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2); |
|
1223 else |
|
1224 iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iCacheBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2); |
|
1225 } |
|
1226 else |
|
1227 { |
|
1228 // |
|
1229 // If not double-buffering, we can read the RMW data of the last block directly |
|
1230 // into the block cache as we know that the data transfer will fit entirely |
|
1231 // within the cache.. |
|
1232 // |
|
1233 const TInt64 lastBlock = iPhysEnd - iBlkLen; // start posn in media to read from |
|
1234 iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iIntBuf + (lastBlock - iPhysStart), iBlkLen >> KMMCardHighCapBlockSizeLog2); |
|
1235 } |
|
1236 |
|
1237 // Kick off the RMW-read operation for the last block... |
|
1238 return EngageAndSetReadRequest(aMedReq); |
|
1239 } |
|
1240 |
|
1241 if (iWtRBM & KWtMinFst) |
|
1242 { |
|
1243 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:Phys write-first-block-only")); |
|
1244 //Overwrite first block with the new data |
|
1245 TInt32 tlen = I64LOW(aStart & iBlkMsk); |
|
1246 TInt32 wlen = UMin(I64LOW((iBlkMsk+1) - tlen), aLength); |
|
1247 |
|
1248 const TInt64 usrOfst = (aStart - iReqStart); |
|
1249 TPtr8 tgt(&iMinorBuf[tlen], I64LOW(wlen)); |
|
1250 |
|
1251 if ( (r = iCurrentReq->ReadRemote(&tgt,I64LOW(usrOfst))) != KErrNone) |
|
1252 return r; |
|
1253 } |
|
1254 |
|
1255 if (iWtRBM & KWtMinLst) |
|
1256 { |
|
1257 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:Phys write-last-block-only")); |
|
1258 iWtRBM &= ~KWtMinLst; |
|
1259 //Overwrite last block with the new data |
|
1260 const TInt64 medEnds = aStart + aLength; |
|
1261 TInt64 tlen = medEnds & iBlkMsk; |
|
1262 |
|
1263 const TInt64 usrOfst = (aStart - iReqStart); |
|
1264 TPtr8 tgt(iCacheBuf, I64LOW(tlen)); |
|
1265 |
|
1266 if ( (r = iCurrentReq->ReadRemote(&tgt,I64LOW(usrOfst+aLength-tlen))) !=KErrNone) |
|
1267 return r; |
|
1268 } |
|
1269 |
|
1270 // no reads required - read data from user buffer and launch write |
|
1271 const TInt64 usrOfst = (aStart - iReqStart); |
|
1272 const TInt64 bufOfst = aStart - iPhysStart; // offset into first sector, not whole buffer |
|
1273 const TInt64 len = UMin(aStart + aLength, iPhysEnd) - iReqCur; |
|
1274 __ASSERT_DEBUG(len > 0, Panic(ELWLength)); |
|
1275 __ASSERT_DEBUG(I64HIGH(usrOfst) == 0, Panic(ELWLength)); |
|
1276 |
|
1277 if (iDoPhysicalAddress) |
|
1278 { |
|
1279 TPhysAddr physAddr = 0; |
|
1280 TInt physLength = 0; |
|
1281 TUint32 physLen = I64LOW(iPhysEnd - iPhysStart); |
|
1282 |
|
1283 if (iWtRBM & KWtMinFst) |
|
1284 { |
|
1285 #if !defined(__WINS__) |
|
1286 physAddr = Epoc::LinearToPhysical((TLinAddr)iMinorBuf); |
|
1287 #else |
|
1288 physAddr = (TPhysAddr)iMinorBuf; |
|
1289 #endif |
|
1290 physLength = iBlkLen; |
|
1291 iBufOfset = I64LOW(iReqStart - iPhysStart); |
|
1292 //iReqCur already set in DoWrite |
|
1293 iFragOfset = iIPCLen = iBlkLen - iBufOfset; |
|
1294 iWtRBM &= ~KWtMinFst; |
|
1295 } |
|
1296 else |
|
1297 { |
|
1298 iFragOfset = I64LOW(usrOfst); |
|
1299 |
|
1300 r = PrepareFirstPhysicalFragment(physAddr, physLength, aLength); |
|
1301 } |
|
1302 |
|
1303 if (r == KErrNone) |
|
1304 { |
|
1305 iDbEnd = iPhysEnd; |
|
1306 iPhysEnd = iPhysStart+physLength; |
|
1307 |
|
1308 if ((TUint32)physLength > physLen) physLength = physLen; // more memory in fragment than required! |
|
1309 |
|
1310 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), (TUint8*) physAddr, physLen >> KMMCardHighCapBlockSizeLog2); |
|
1311 iSession->Command().iFlags|= KMMCCmdFlagPhysAddr; |
|
1312 iSession->EnableDoubleBuffering(physLength >> KDiskSectorShift); |
|
1313 } |
|
1314 else |
|
1315 { |
|
1316 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lw:Phys:%d", r)); |
|
1317 return r; |
|
1318 } |
|
1319 } // if (iDoPhysicalAddress) |
|
1320 else |
|
1321 { |
|
1322 TPtr8 tgt(&iIntBuf[bufOfst], I64LOW(len)); |
|
1323 |
|
1324 r = ReadDataFromUser(tgt, I64LOW(usrOfst)); |
|
1325 if (r == KErrNone) |
|
1326 { |
|
1327 if(!iDoDoubleBuffer) |
|
1328 { |
|
1329 // EPBUSM automatically uses CMD24 instead of CMD25 for single block writes |
|
1330 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); |
|
1331 } |
|
1332 else |
|
1333 { |
|
1334 // |
|
1335 // When double-buffering, set up the data transfer command to the entire |
|
1336 // request range. and flag the session to enable double-buffering (as well |
|
1337 // as specifying the length of each double-buffered transfer as calculated |
|
1338 // in 'len' above). This is performed only once - the double-buffering |
|
1339 // is subsequently handled within the DoDataTransferCallback function. |
|
1340 // |
|
1341 iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW((((iDbEnd + iBlkMsk) & ~iBlkMsk) - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); |
|
1342 iSession->EnableDoubleBuffering(I64LOW((len + iBlkMsk) & ~iBlkMsk) >> KDiskSectorShift); |
|
1343 |
|
1344 // ...and switch to the 'second' buffer, which will be populated in the |
|
1345 // data transfer callback in parallel with hardware transfer of the first. |
|
1346 iSecondBuffer = ETrue; |
|
1347 } |
|
1348 } |
|
1349 } |
|
1350 |
|
1351 //Reliable Write only supported by v4.3+ MMC media |
|
1352 if (iCard->ExtendedCSD().ExtendedCSDRev() >= 3) |
|
1353 { |
|
1354 // One request, i.e. not end of previous DB request |
|
1355 // 512 Bytes long when sector aligned |
|
1356 if ( ( I64LOW(iPhysEnd - iPhysStart) == iBlkLen) && ((iReqStart & ~iBlkMsk) == iPhysStart) ) |
|
1357 { |
|
1358 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:AtomicWrite")); |
|
1359 iSession->Command().iFlags|= KMMCCmdFlagReliableWrite; |
|
1360 } |
|
1361 } |
|
1362 |
|
1363 // Engage the data transfer session... |
|
1364 r = EngageAndSetWriteRequest(aMedReq); |
|
1365 } // if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone) |
|
1366 |
|
1367 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lw:%d", r)); |
|
1368 |
|
1369 return r; |
|
1370 } |
|
1371 |
|
1372 TInt DMmcMediaDriverFlash::PartitionInfo(TPartitionInfo& anInfo) |
|
1373 // |
|
1374 // Read the partition information for the media. If the user supplied a password, |
|
1375 // then unlock the card before trying to read the first sector. |
|
1376 // |
|
1377 { |
|
1378 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rpi")); |
|
1379 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(ERPIInUse)); |
|
1380 |
|
1381 iPartitionInfo = &anInfo; |
|
1382 |
|
1383 if(iMmcPartitionInfo) |
|
1384 { |
|
1385 // If this is an embedded device, use the custom formatting function: |
|
1386 TInt r = iMmcPartitionInfo->PartitionInfo(*iPartitionInfo, iSessionEndCallBack); |
|
1387 |
|
1388 iHiddenSectors = 0; // Not used for internal media |
|
1389 |
|
1390 if (KErrNone == r) |
|
1391 iMedReq = EMReqEMMCPtnInfo; |
|
1392 |
|
1393 return(r); |
|
1394 } |
|
1395 |
|
1396 // Assume MBR will be present or is not required |
|
1397 iMbrMissing = EFalse; |
|
1398 |
|
1399 // If media driver is persistent (see EMediaDriverPersistent), |
|
1400 // the card may have changed since last power down, so reset CID |
|
1401 iSession->SetCard(iCard); |
|
1402 |
|
1403 TInt r = LaunchRPIRead(); |
|
1404 |
|
1405 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rpi:%d", r)); |
|
1406 |
|
1407 if(r == KErrLocked) |
|
1408 { |
|
1409 // If the media is locked, we present a default partition entry to the local |
|
1410 // media subsystem, which will be updated when the media is finally unlocked. |
|
1411 r = CreateDefaultPartition(); |
|
1412 if (r != KErrNone) |
|
1413 return r; |
|
1414 return KErrLocked; |
|
1415 } |
|
1416 |
|
1417 // KErrNone indicates asynchronous completion |
|
1418 return r; |
|
1419 } |
|
1420 |
|
1421 TInt DMmcMediaDriverFlash::LaunchRPIUnlock(TLocalDrivePasswordData& aPasswordData) |
|
1422 { |
|
1423 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lru:%d,%d", iCard->IsReady(), iCard->IsLocked())); |
|
1424 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
1425 |
|
1426 TInt r = KErrNone; |
|
1427 |
|
1428 // CMD42 is an adtc, so check state in same way as for write |
|
1429 if ((r = CheckDevice(EMReqTypeUnlockPswd)) == KErrNone) |
|
1430 { |
|
1431 r = Stack().MMCSocket()->PrepareStore(CardNum(), DLocalDrive::EPasswordUnlock, aPasswordData); |
|
1432 |
|
1433 if (r == KErrNone) |
|
1434 { |
|
1435 TMediaPassword curPwd; |
|
1436 |
|
1437 curPwd = *aPasswordData.iOldPasswd; |
|
1438 |
|
1439 TInt curPwdLen = curPwd.Length(); |
|
1440 TInt blockLen = 2 + curPwdLen; |
|
1441 |
|
1442 TPtr8 pbuf(&iMinorBuf[0], 2, blockLen); |
|
1443 pbuf[0] = 0; // LOCK_UNLOCK = 0; SET_PWD = 0 |
|
1444 pbuf[1] = static_cast<TUint8>(curPwdLen); |
|
1445 pbuf.Append(curPwd); |
|
1446 iSession->SetupCIMLockUnlock(blockLen, iMinorBuf); |
|
1447 |
|
1448 r = EngageAndSetWriteRequest(EMReqUpdatePtnInfo); |
|
1449 } |
|
1450 } |
|
1451 |
|
1452 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lru:%d", r)); |
|
1453 return r; |
|
1454 } |
|
1455 |
|
1456 |
|
1457 TInt DMmcMediaDriverFlash::LaunchRPIRead() |
|
1458 // |
|
1459 // launch read request on first KDiskSectorSize (512) bytes |
|
1460 // |
|
1461 { |
|
1462 __KTRACE_OPT(KPBUSDRV, Kern::Printf((">mmd:lrr"))); |
|
1463 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
1464 |
|
1465 // the partition information is read before any other area is read from / |
|
1466 // written to, and so does not need to maintain cache coherence. Therefore |
|
1467 // it can safely use the minor buffer. |
|
1468 |
|
1469 TInt r; |
|
1470 if ((r = CheckDevice(EMReqTypeNormalRd)) == KErrNone) |
|
1471 { |
|
1472 iIntBuf = iMinorBuf; |
|
1473 iSession->SetupCIMReadBlock(0, iIntBuf); // aBlocks = 1 |
|
1474 r = EngageAndSetReadRequest(EMReqPtnInfo); |
|
1475 } |
|
1476 |
|
1477 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lrr:%d", r)); |
|
1478 return r; |
|
1479 } |
|
1480 |
|
1481 |
|
1482 TInt DMmcMediaDriverFlash::LaunchRPIErase() |
|
1483 { |
|
1484 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lre:%d,%d", iCard->IsReady(), iCard->IsLocked())); |
|
1485 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
1486 |
|
1487 TInt r = KErrNone; |
|
1488 |
|
1489 // CMD42 is an adtc, so check state in same way as for write |
|
1490 if ((r = CheckDevice(EMReqTypeUnlockPswd)) == KErrNone) |
|
1491 { |
|
1492 if(iCard->IsWriteProtected()) |
|
1493 { |
|
1494 r = KErrAccessDenied; |
|
1495 } |
|
1496 else |
|
1497 { |
|
1498 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:df:EMReqForceErase")); |
|
1499 iMinorBuf[0] = KMMCLockUnlockErase; |
|
1500 iSession->SetupCIMLockUnlock(1, iMinorBuf); |
|
1501 r = EngageAndSetWriteRequest(EMReqForceErase); |
|
1502 } |
|
1503 } |
|
1504 |
|
1505 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lru:%d", r)); |
|
1506 return r; |
|
1507 } |
|
1508 |
|
1509 |
|
1510 TInt DMmcMediaDriverFlash::DecodePartitionInfo() |
|
1511 // |
|
1512 // decode partition info that was read into internal buffer |
|
1513 // |
|
1514 { |
|
1515 TInt partitionCount=iPartitionInfo->iPartitionCount=0; |
|
1516 TInt defaultPartitionNumber=-1; |
|
1517 TMBRPartitionEntry* pe; |
|
1518 const TUint KMBRFirstPartitionOffsetAligned = KMBRFirstPartitionOffset & ~3; |
|
1519 TInt i; |
|
1520 |
|
1521 // Read of the first sector successful so check for a Master Boot Record |
|
1522 if (*(TUint16*)(&iIntBuf[KMBRSignatureOffset])!=0xAA55) |
|
1523 goto mbr_done; |
|
1524 |
|
1525 __ASSERT_COMPILE(KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry) <= KMBRSignatureOffset); |
|
1526 |
|
1527 memmove(&iIntBuf[0], &iIntBuf[2], |
|
1528 KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry)); |
|
1529 |
|
1530 |
|
1531 for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]); |
|
1532 pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++) |
|
1533 { |
|
1534 if (pe->IsDefaultBootPartition()) |
|
1535 { |
|
1536 SetPartitionEntry(&iPartitionInfo->iEntry[0],pe->iFirstSector,pe->iNumSectors); |
|
1537 defaultPartitionNumber=i; |
|
1538 partitionCount++; |
|
1539 break; |
|
1540 } |
|
1541 } |
|
1542 |
|
1543 // Now add any other partitions |
|
1544 for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]); |
|
1545 pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++) |
|
1546 { |
|
1547 TBool validPartition = ETrue; // assume partition valid |
|
1548 |
|
1549 if (defaultPartitionNumber==i) |
|
1550 { |
|
1551 // Already sorted |
|
1552 } |
|
1553 |
|
1554 // FAT partition ? |
|
1555 else if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition()) |
|
1556 { |
|
1557 SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors); |
|
1558 __KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: FAT partition found at sector #%u", pe->iFirstSector)); |
|
1559 partitionCount++; |
|
1560 } |
|
1561 else |
|
1562 { |
|
1563 validPartition = EFalse; |
|
1564 } |
|
1565 |
|
1566 if (validPartition && partitionCount == 1) |
|
1567 iHiddenSectors = pe->iFirstSector; |
|
1568 |
|
1569 } |
|
1570 |
|
1571 // Check the validity of the partition address boundaries |
|
1572 // If there is any |
|
1573 if(partitionCount > 0) |
|
1574 { |
|
1575 const TInt64 deviceSize = iCard->DeviceSize64(); |
|
1576 TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1]; |
|
1577 // Check that the card address space boundary is not exceeded by the last partition |
|
1578 // In case of only 1 partition in the media check also it |
|
1579 if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize) |
|
1580 { |
|
1581 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space")); |
|
1582 // Adjust the partition length to card address boundary |
|
1583 part.iPartitionLen = (deviceSize - part.iPartitionBaseAddr); |
|
1584 |
|
1585 // Check that the base address contained valid information |
|
1586 if(part.iPartitionLen <= 0) |
|
1587 { |
|
1588 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Invalid base address")); |
|
1589 // Invalid MBR - assume the boot sector is in the first sector |
|
1590 defaultPartitionNumber =-1; |
|
1591 partitionCount=0; |
|
1592 } |
|
1593 } |
|
1594 // More than one partition. Go through all of them |
|
1595 if (partitionCount > 0) |
|
1596 { |
|
1597 for(i=partitionCount-1; i>0; i--) |
|
1598 { |
|
1599 const TPartitionEntry& curr = iPartitionInfo->iEntry[i]; |
|
1600 TPartitionEntry& prev = iPartitionInfo->iEntry[i-1]; |
|
1601 // Check if partitions overlap |
|
1602 if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen)) |
|
1603 { |
|
1604 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Overlapping partitions")); |
|
1605 // Adjust the partition length to not overlap the next partition |
|
1606 prev.iPartitionLen = (curr.iPartitionBaseAddr - prev.iPartitionBaseAddr); |
|
1607 |
|
1608 // Check that the base address contained valid information |
|
1609 if(prev.iPartitionLen <= 0) |
|
1610 { |
|
1611 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Invalid base address")); |
|
1612 // Invalid MBR - assume the boot sector is in the first sector |
|
1613 defaultPartitionNumber=(-1); |
|
1614 partitionCount=0; |
|
1615 } |
|
1616 } |
|
1617 } |
|
1618 } |
|
1619 } |
|
1620 |
|
1621 mbr_done: |
|
1622 if (defaultPartitionNumber==(-1) && partitionCount==0) |
|
1623 { |
|
1624 __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc:PartitionInfo no MBR")); |
|
1625 if (MBRMandatory(iCard)) |
|
1626 { |
|
1627 // If the MBR is missing AND is required, we present a default partition entry to the local |
|
1628 // media subsystem, which will be updated when the media is finally formatted |
|
1629 __KTRACE_OPT(KPBUSDRV, Kern::Printf("MBR mandatory, defining space for MBR + default partition")); |
|
1630 iMbrMissing = ETrue; |
|
1631 TInt r = CreateDefaultPartition(); |
|
1632 if (r != KErrNone) |
|
1633 return r; |
|
1634 } |
|
1635 else |
|
1636 { |
|
1637 // Assume it has no MBR, and the Boot Sector is in the 1st sector |
|
1638 SetPartitionEntry(&iPartitionInfo->iEntry[0],0,I64LOW(iCard->DeviceSize64()>>KDiskSectorShift)); |
|
1639 iHiddenSectors=0; |
|
1640 } |
|
1641 partitionCount=1; |
|
1642 } |
|
1643 |
|
1644 iPartitionInfo->iPartitionCount=partitionCount; |
|
1645 iPartitionInfo->iMediaSizeInBytes=TotalSizeInBytes(); |
|
1646 |
|
1647 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<Mmc:PartitionInfo (C:%d)",iPartitionInfo->iPartitionCount)); |
|
1648 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition1 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[0].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[0].iPartitionLen))); |
|
1649 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition2 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[1].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[1].iPartitionLen))); |
|
1650 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition3 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[2].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[2].iPartitionLen))); |
|
1651 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Partition4 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[3].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[3].iPartitionLen))); |
|
1652 |
|
1653 #ifdef _DEBUG |
|
1654 TMBRPartitionEntry cPe; |
|
1655 if(GetDefaultPartitionInfo(cPe) == KErrNone) |
|
1656 { |
|
1657 pe = (TMBRPartitionEntry*)(&iIntBuf[0]); |
|
1658 |
|
1659 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------")); |
|
1660 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- Partition Entry Validation/Comparison --")); |
|
1661 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------")); |
|
1662 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iX86BootIndicator [%02x:%02x] %c -", pe->iX86BootIndicator, cPe.iX86BootIndicator, pe->iX86BootIndicator == cPe.iX86BootIndicator ? ' ' : 'X')); |
|
1663 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartHead [%02x:%02x] %c -", pe->iStartHead, cPe.iStartHead, pe->iStartHead == cPe.iStartHead ? ' ' : 'X')); |
|
1664 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartSector [%02x:%02x] %c -", pe->iStartSector, cPe.iStartSector, pe->iStartSector == cPe.iStartSector ? ' ' : 'X')); |
|
1665 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iStartCylinder [%02x:%02x] %c -", pe->iStartCylinder, cPe.iStartCylinder, pe->iStartCylinder == cPe.iStartCylinder ? ' ' : 'X')); |
|
1666 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iPartitionType [%02x:%02x] %c -", pe->iPartitionType, cPe.iPartitionType, pe->iPartitionType == cPe.iPartitionType ? ' ' : 'X')); |
|
1667 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndHead [%02x:%02x] %c -", pe->iEndHead, cPe.iEndHead, pe->iEndHead == cPe.iEndHead ? ' ' : 'X')); |
|
1668 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndSector [%02x:%02x] %c -", pe->iEndSector, cPe.iEndSector, pe->iEndSector == cPe.iEndSector ? ' ' : 'X')); |
|
1669 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iEndCylinder [%02x:%02x] %c -", pe->iEndCylinder, cPe.iEndCylinder, pe->iEndCylinder == cPe.iEndCylinder ? ' ' : 'X')); |
|
1670 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iFirstSector [%08x:%08x] %c -", pe->iFirstSector, cPe.iFirstSector, pe->iFirstSector == cPe.iFirstSector ? ' ' : 'X')); |
|
1671 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iNumSectors [%08x:%08x] %c -", pe->iNumSectors, cPe.iNumSectors, pe->iNumSectors == cPe.iNumSectors ? ' ' : 'X')); |
|
1672 __KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------")); |
|
1673 } |
|
1674 #endif |
|
1675 |
|
1676 return(KErrNone); |
|
1677 } |
|
1678 |
|
1679 |
|
1680 TInt DMmcMediaDriverFlash::WritePartitionInfo() |
|
1681 /** |
|
1682 Write the default partition table to freshly formatted media |
|
1683 @return Standard Symbian OS Error Code |
|
1684 */ |
|
1685 { |
|
1686 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:wpi")); |
|
1687 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
1688 |
|
1689 TMBRPartitionEntry partitionEntry; |
|
1690 TInt err = GetDefaultPartitionInfo(partitionEntry); |
|
1691 if(err == KErrNone) |
|
1692 { |
|
1693 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:MBR/Partition Table")); |
|
1694 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Boot ID : %02xh", partitionEntry.iX86BootIndicator)); |
|
1695 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Head : %02xh", partitionEntry.iStartHead)); |
|
1696 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Sector : %02xh", partitionEntry.iStartSector)); |
|
1697 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Start Cyclinder : %02xh", partitionEntry.iStartCylinder)); |
|
1698 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" System ID : %02xh", partitionEntry.iPartitionType)); |
|
1699 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Head : %02xh", partitionEntry.iEndHead)); |
|
1700 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Sector : %02xh", partitionEntry.iEndSector)); |
|
1701 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" End Cyclinder : %02xh", partitionEntry.iEndCylinder)); |
|
1702 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Relative Sector : %08xh", partitionEntry.iFirstSector)); |
|
1703 __KTRACE_OPT(KPBUSDRV, Kern::Printf(" Number of Sectors: %08xh", partitionEntry.iNumSectors)); |
|
1704 |
|
1705 // |
|
1706 // Clear all other partition entries and align the partition info into the minor buffer for writing... |
|
1707 // |
|
1708 memclr(iMinorBuf, KDiskSectorSize); |
|
1709 memcpy(&iMinorBuf[KMBRFirstPartitionEntry], &partitionEntry, sizeof(TMBRPartitionEntry)); |
|
1710 |
|
1711 *(TUint16*)(&iMinorBuf[KMBRSignatureOffset]) = 0xAA55; |
|
1712 |
|
1713 iSession->SetupCIMWriteBlock(0, iMinorBuf); |
|
1714 |
|
1715 // |
|
1716 // Write the partition table and engage the read to validate and complete the mount process |
|
1717 // |
|
1718 iMbrMissing = EFalse; |
|
1719 iCreateMbr = EFalse; |
|
1720 err = EngageAndSetWriteRequest(EMReqUpdatePtnInfo); |
|
1721 } |
|
1722 |
|
1723 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:wpi:%d", err)); |
|
1724 |
|
1725 return(err); |
|
1726 } |
|
1727 |
|
1728 |
|
1729 TInt DMmcMediaDriverFlash::CreateDefaultPartition() |
|
1730 { |
|
1731 TMBRPartitionEntry defPartition; |
|
1732 TInt r = GetDefaultPartitionInfo(defPartition); |
|
1733 if (r == KErrNone) |
|
1734 { |
|
1735 SetPartitionEntry(&iPartitionInfo->iEntry[0], defPartition.iFirstSector, defPartition.iNumSectors); |
|
1736 iHiddenSectors = defPartition.iFirstSector; |
|
1737 iPartitionInfo->iPartitionCount = 1; |
|
1738 iPartitionInfo->iMediaSizeInBytes = TotalSizeInBytes(); |
|
1739 } |
|
1740 return r; |
|
1741 } |
|
1742 |
|
1743 TInt DMmcMediaDriverFlash::GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry) |
|
1744 /** |
|
1745 Calculates the default patition information for an specific card. |
|
1746 @param aPartitionEntry The TMBRPartitionEntry to be filled in with the format parameters |
|
1747 @return Standard Symbian OS Error Code |
|
1748 */ |
|
1749 { |
|
1750 memclr(&aPartitionEntry, sizeof(TMBRPartitionEntry)); |
|
1751 TUint16 reservedSectors; // Not used |
|
1752 return GetMediaDefaultPartitionInfo(aPartitionEntry, reservedSectors, iCard); |
|
1753 } |
|
1754 |
|
1755 |
|
1756 void DMmcMediaDriverFlash::SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors) |
|
1757 // |
|
1758 // auxiliary static function to record partition information in TPartitionEntry object |
|
1759 // |
|
1760 { |
|
1761 aEntry->iPartitionBaseAddr=aFirstSector; |
|
1762 aEntry->iPartitionBaseAddr<<=KDiskSectorShift; |
|
1763 aEntry->iPartitionLen=aNumSectors; |
|
1764 aEntry->iPartitionLen<<=KDiskSectorShift; |
|
1765 aEntry->iPartitionType=KPartitionTypeFAT12; |
|
1766 } |
|
1767 |
|
1768 TInt DMmcMediaDriverFlash::DoPasswordOp() |
|
1769 { |
|
1770 // Reconstruct password data structure in our address space |
|
1771 TLocalDrivePasswordData clientData; |
|
1772 TInt r = iCurrentReq->ReadRemoteRaw(&clientData, sizeof(TLocalDrivePasswordData)); |
|
1773 |
|
1774 TMediaPassword oldPassword; |
|
1775 if (r == KErrNone) |
|
1776 r = iCurrentReq->ReadRemote(clientData.iOldPasswd, &oldPassword); |
|
1777 |
|
1778 TMediaPassword newPassword; |
|
1779 if (r == KErrNone) |
|
1780 r = iCurrentReq->ReadRemote(clientData.iNewPasswd, &newPassword); |
|
1781 |
|
1782 TLocalDrivePasswordData passData(oldPassword, newPassword, clientData.iStorePasswd); |
|
1783 |
|
1784 if (r == KErrNone) |
|
1785 { |
|
1786 TInt id=iCurrentReq->Id(); |
|
1787 switch (id) |
|
1788 { |
|
1789 case DLocalDrive::EPasswordUnlock: |
|
1790 r = LaunchRPIUnlock(passData); |
|
1791 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rpi:%d", r)); |
|
1792 break; |
|
1793 case DLocalDrive::EPasswordLock: |
|
1794 case DLocalDrive::EPasswordClear: |
|
1795 PasswordControl(id, passData); |
|
1796 break; |
|
1797 } |
|
1798 } |
|
1799 |
|
1800 // This will complete the request in the event of an error |
|
1801 if(r != KErrNone) |
|
1802 PartitionInfoComplete(r); |
|
1803 |
|
1804 return KErrNone; // ensures to indicate asynchronoous completion |
|
1805 } |
|
1806 |
|
1807 void DMmcMediaDriverFlash::PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData) |
|
1808 // |
|
1809 // Change a card's password, or clear the pasword from a locked card. The card |
|
1810 // must be unlocked for this function. A locked card is unlocked when it is mounted, |
|
1811 // to read the partition information. This is done from ReadPartitionInfo() and |
|
1812 // LaunchRPIUnlock(). |
|
1813 // |
|
1814 { |
|
1815 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:pc:%d", (TInt) aFunc)); |
|
1816 __ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EPCInUse)); |
|
1817 __ASSERT_DEBUG(aFunc == DLocalDrive::EPasswordLock || aFunc == DLocalDrive::EPasswordClear, Panic(EPCFunc)); |
|
1818 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
1819 |
|
1820 TInt r; |
|
1821 |
|
1822 if ((r = CheckDevice(EMReqTypeChangePswd)) == KErrNone) |
|
1823 { |
|
1824 // check if the current password is correct here. (This makes the |
|
1825 // clear operation redundant only if the password is stored and it |
|
1826 // is wrong.) Complete with same value as DoSessionEndDfc() would. |
|
1827 |
|
1828 TMediaPassword curPwd; |
|
1829 |
|
1830 curPwd = *aData.iOldPasswd; |
|
1831 TInt curPwdLen = curPwd.Length(); |
|
1832 TInt blockLen; |
|
1833 |
|
1834 if (!(iCard->iFlags & KMMCardIsLockable)) |
|
1835 r = KErrNotSupported; |
|
1836 else if (Stack().PasswordStore()->IsMappingIncorrect(iCard->CID(), curPwd)) |
|
1837 r = KErrAccessDenied; |
|
1838 else |
|
1839 { |
|
1840 if ((r = Stack().MMCSocket()->PrepareStore(CardNum(), aFunc, aData/*, aThread*/)) == KErrNone) |
|
1841 { |
|
1842 switch (aFunc) |
|
1843 { |
|
1844 case DLocalDrive::EPasswordLock: |
|
1845 { |
|
1846 TMediaPassword newPwd; |
|
1847 newPwd = *aData.iNewPasswd; |
|
1848 TInt newPwdLen = newPwd.Length(); |
|
1849 blockLen = 1 + 1 + curPwdLen + newPwdLen; |
|
1850 |
|
1851 #ifndef __EPOC32__ |
|
1852 TUint16 env_Var[]=L"_EPOC_PWD_LEN"; |
|
1853 TUint16 env_Val[2]; |
|
1854 env_Val[0]=(TUint16)(curPwdLen+1); |
|
1855 env_Val[1]=0;//make a null terminated string |
|
1856 r=SetEnvironmentVariable(env_Var,&env_Val[0]); |
|
1857 __ASSERT_DEBUG(r!=0, Panic(EPCFunc)); |
|
1858 |
|
1859 #endif |
|
1860 |
|
1861 TPtr8 pbuf(&iMinorBuf[0], 2, blockLen); |
|
1862 pbuf[0] = KMMCLockUnlockSetPwd; // LOCK_UNLOCK = 0, SET_PWD = 1 |
|
1863 pbuf[1] = static_cast<TUint8>(curPwdLen + newPwdLen); |
|
1864 pbuf.Append(curPwd); |
|
1865 pbuf.Append(newPwd); |
|
1866 } |
|
1867 break; |
|
1868 |
|
1869 case DLocalDrive::EPasswordClear: |
|
1870 { |
|
1871 blockLen = 1 + 1 + curPwdLen; |
|
1872 |
|
1873 TPtr8 pbuf(&iMinorBuf[0], 2, blockLen); |
|
1874 pbuf[0] = KMMCLockUnlockClrPwd; // LOCK_UNLOCK = dc, CLR_PWD = 1 |
|
1875 pbuf[1] = static_cast<TUint8>(curPwdLen); |
|
1876 pbuf.Append(curPwd); |
|
1877 } |
|
1878 break; |
|
1879 |
|
1880 default: |
|
1881 // DLocalDrive::EPasswordUnlock is not handled. This avoids warnings for unused |
|
1882 // case, and uninitialized variable. |
|
1883 blockLen = 0; |
|
1884 break; |
|
1885 } // switch (aFunc) |
|
1886 |
|
1887 iSession->SetupCIMLockUnlock(blockLen, iMinorBuf); |
|
1888 r = EngageAndSetWriteRequest(EMReqPswdCtrl); |
|
1889 } // if ((r = Stack().PrepareStore(CardNum(), aFunc, aData, aThread)) == KErrNone) |
|
1890 } // else (Stack().IsMappingIncorrect(iCard->CID(), curPwd)) |
|
1891 } // (r = CheckDevice(EMReqTypeChangePswd)) == KErrNone |
|
1892 |
|
1893 // complete immediately if error occured |
|
1894 if (r != KErrNone) |
|
1895 CompleteRequest(r); |
|
1896 |
|
1897 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:pc:%d", r)); |
|
1898 } |
|
1899 |
|
1900 |
|
1901 // ---- device status, callback DFC ---- |
|
1902 |
|
1903 TInt DMmcMediaDriverFlash::CheckDevice(TMediaReqType aReqType) |
|
1904 // |
|
1905 // Check the device before initiating a command |
|
1906 // |
|
1907 { |
|
1908 |
|
1909 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:cd:%d",aReqType)); |
|
1910 |
|
1911 TInt r=KErrNone; |
|
1912 |
|
1913 if (!iCard->IsReady()) |
|
1914 r=KErrNotReady; |
|
1915 |
|
1916 // The card must be locked if attempting to unlock during RPI, and |
|
1917 // unlocked at all other times. |
|
1918 else if (aReqType!=EMReqTypeUnlockPswd && iCard->IsLocked()) |
|
1919 r=KErrLocked; |
|
1920 // Don't perform Password setting for WriteProtected cards, |
|
1921 // unable to recover (ForcedErase) if password lost. |
|
1922 else if (aReqType==EMReqTypeChangePswd) |
|
1923 { |
|
1924 if (iCard->MediaType()==EMultiMediaROM) |
|
1925 { |
|
1926 r=KErrAccessDenied; |
|
1927 } |
|
1928 } |
|
1929 else if (iMbrMissing && aReqType==EMReqTypeNormalRd) |
|
1930 r=KErrCorrupt; |
|
1931 |
|
1932 #if !defined(__WINS__) |
|
1933 // Don't perform write/password operations when the battery is low |
|
1934 // else if (aReqType!=EMReqTypeNormalRd && Hal::MainBatteryStatus()<ELow && !Hal::ExternalPowerPresent()) |
|
1935 // r=KErrBadPower; |
|
1936 #endif |
|
1937 // Don't perform write operations when the mechanical write protect switch is set |
|
1938 else if (aReqType==EMReqTypeNormalWr && iCard->IsWriteProtected()) |
|
1939 r=KErrAccessDenied; |
|
1940 // Don't perform write/format operations on MMC ROM cards |
|
1941 else if (iMediaType==EMultiMediaROM && aReqType == EMReqTypeNormalWr) |
|
1942 r=KErrAccessDenied; |
|
1943 |
|
1944 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:cd:%d", r)); |
|
1945 return(r); |
|
1946 } |
|
1947 |
|
1948 void DMmcMediaDriverFlash::SessionEndCallBack(TAny* aMediaDriver) |
|
1949 // |
|
1950 // called by EPBUS when a single session has finished. Queues DFC to launch |
|
1951 // next session or to complete client request. |
|
1952 // |
|
1953 { |
|
1954 DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver); |
|
1955 __ASSERT_DEBUG(! md.iSessionEndDfc.Queued(), Panic(ESECBQueued)); |
|
1956 md.iSessionEndDfc.Enque(); |
|
1957 } |
|
1958 |
|
1959 |
|
1960 void DMmcMediaDriverFlash::SessionEndDfc(TAny* aMediaDriver) |
|
1961 { |
|
1962 static_cast<DMmcMediaDriverFlash*>(aMediaDriver)->DoSessionEndDfc(); |
|
1963 } |
|
1964 |
|
1965 |
|
1966 void DMmcMediaDriverFlash::DoSessionEndDfc() |
|
1967 // |
|
1968 // launch next session or complete client request |
|
1969 // |
|
1970 { |
|
1971 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dsed:%d", CurrentRequest())); |
|
1972 |
|
1973 TInt r=KErrNone; |
|
1974 |
|
1975 EndInCritical(); |
|
1976 |
|
1977 // Abort if writing or formatting and power has gone down |
|
1978 if (!Kern::PowerGood() && CurrentRequest()!=EMReqRead) |
|
1979 r=KErrAbort; |
|
1980 // Return KErrNotReady if we have has a deferred media change |
|
1981 if (!iCard->IsReady()) |
|
1982 r=KErrNotReady; |
|
1983 // if stack has powered down session pointer will be NULL |
|
1984 if (iSession == NULL) |
|
1985 r = KErrNotReady; |
|
1986 |
|
1987 TBool complete = ETrue; |
|
1988 |
|
1989 if (r==KErrNone) |
|
1990 { |
|
1991 r = iSession->EpocErrorCode(); |
|
1992 |
|
1993 switch (CurrentRequest()) |
|
1994 { |
|
1995 case EMReqRead: |
|
1996 { |
|
1997 if (r != KErrNone) // abort if MMC error |
|
1998 break; |
|
1999 |
|
2000 if(iDoDoubleBuffer) |
|
2001 { |
|
2002 // |
|
2003 // This is the end of a double-buffered transfer. |
|
2004 // - Now we have two buffers to copy back to the user... |
|
2005 // |
|
2006 TUint8* bufPtr = iIntBuf + (iSecondBuffer ? (iMaxBufSize >> 1) : 0); |
|
2007 if((r = WriteDataToUser(bufPtr)) == KErrNone) |
|
2008 { |
|
2009 MarkBlocks(iReqCur, iPhysEnd, CchMemToIdx(bufPtr)); |
|
2010 |
|
2011 iReqCur = iPhysEnd; |
|
2012 iPhysEnd = iDbEnd; |
|
2013 |
|
2014 bufPtr = iIntBuf + (iSecondBuffer ? 0 : (iMaxBufSize >> 1)); |
|
2015 if((r = WriteDataToUser(bufPtr)) == KErrNone) |
|
2016 { |
|
2017 MarkBlocks(iReqCur, (iPhysEnd + iBlkMsk) & ~iBlkMsk, CchMemToIdx(bufPtr)); |
|
2018 } |
|
2019 } |
|
2020 iDoDoubleBuffer = EFalse; |
|
2021 } |
|
2022 else if (iDoPhysicalAddress) |
|
2023 { |
|
2024 if (iRdROB & KIPCWrite) |
|
2025 { |
|
2026 // partial end point |
|
2027 TInt len = I64LOW(iReqEnd & iBlkMsk); |
|
2028 const TInt ofset = I64LOW(iPhysEnd - iBlkLen - iReqStart); |
|
2029 |
|
2030 TPtrC8 extrView(iIntBuf, len); |
|
2031 r = iCurrentReq->WriteRemote(&extrView,ofset); |
|
2032 } |
|
2033 // Reset attributes |
|
2034 iRdROB = 0; |
|
2035 iFragOfset = iIPCLen = iBufOfset = 0; |
|
2036 iReqCur = iPhysEnd = iReqEnd; |
|
2037 iDoPhysicalAddress = EFalse; |
|
2038 } |
|
2039 else |
|
2040 { |
|
2041 r = WriteDataToUser(&iIntBuf[I64LOW(iReqCur - iPhysStart)]); |
|
2042 } |
|
2043 |
|
2044 if (r != KErrNone) |
|
2045 break; |
|
2046 |
|
2047 // if there is more information to read for the user then engage another session |
|
2048 if ((iReqCur = iPhysEnd) < iReqEnd) |
|
2049 { |
|
2050 TBool allDone = EFalse; |
|
2051 if ( ((r = ReadDataUntilCacheExhausted(&allDone)) == KErrNone) && !allDone) |
|
2052 { |
|
2053 iPhysStart = iReqCur & ~iBlkMsk; |
|
2054 TUint32 length = I64LOW(iReqEnd - iReqCur); |
|
2055 |
|
2056 if ( (iReqEnd - iPhysStart) > iMaxBufSize && iSocket->SupportsDoubleBuffering() && !iReadToEndOfCard) |
|
2057 r = LaunchDBRead(); |
|
2058 else |
|
2059 r = LaunchRead(iReqCur, length); |
|
2060 |
|
2061 if ( r == KErrNone) |
|
2062 complete = EFalse; |
|
2063 } |
|
2064 } |
|
2065 } |
|
2066 break; |
|
2067 |
|
2068 case EMReqWrite: |
|
2069 { |
|
2070 if (r != KErrNone) // abort if MMC error |
|
2071 { |
|
2072 break; |
|
2073 } |
|
2074 |
|
2075 if (iWtRBM == 0) |
|
2076 { |
|
2077 iReqCur = iPhysEnd; |
|
2078 iDoDoubleBuffer = EFalse; |
|
2079 iDoPhysicalAddress = EFalse; |
|
2080 iRdROB = 0; |
|
2081 iFragOfset = iIPCLen = iBufOfset = 0; |
|
2082 } |
|
2083 // clear current RBM flag |
|
2084 else |
|
2085 { |
|
2086 if (iWtRBM & KWtRBMFst) |
|
2087 { |
|
2088 iWtRBM &= ~KWtRBMFst; |
|
2089 } |
|
2090 else if (iWtRBM & KWtRBMLst) |
|
2091 { |
|
2092 iWtRBM &= ~KWtRBMLst; |
|
2093 } |
|
2094 } |
|
2095 |
|
2096 // advance media position if just finished write, as opposed to read-before-modify |
|
2097 if (iReqCur < iReqEnd) |
|
2098 { |
|
2099 if ((r = LaunchWrite(iReqCur, I64LOW(iReqEnd - iReqCur), EMReqWrite)) == KErrNone) |
|
2100 { |
|
2101 complete = EFalse; |
|
2102 } |
|
2103 |
|
2104 complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse; |
|
2105 } |
|
2106 } |
|
2107 break; |
|
2108 |
|
2109 case EMReqFormat: |
|
2110 { |
|
2111 if (r != KErrNone) // abort if MMC error |
|
2112 break; |
|
2113 |
|
2114 if ((iEraseUnitMsk == KMaxTUint64) || // no erase unit defined (Erase Class Commands not supported) ? |
|
2115 (iPhysEnd == iReqEnd) || // finshed already ? |
|
2116 ((iPhysStart & iEraseUnitMsk) == 0 && (iPhysEnd & iEraseUnitMsk) == 0)) |
|
2117 { |
|
2118 iReqCur = iPhysEnd; |
|
2119 } |
|
2120 else |
|
2121 { |
|
2122 // Formating to a mis-aligned boundary, so we can't make best use of |
|
2123 // multiple erase blocks. We shall simply erase up to the next block |
|
2124 // boundary, and return the adjustment info to the file system |
|
2125 r = I64LOW(iPhysEnd - iPhysStart); |
|
2126 iReqCur = iReqEnd; |
|
2127 } |
|
2128 |
|
2129 if(r == KErrNone) |
|
2130 { |
|
2131 // advance media position if just finished write, as opposed to read-before-modify |
|
2132 if (iReqCur < iReqEnd) |
|
2133 { |
|
2134 if ((r = LaunchFormat(iReqCur, I64LOW(iReqEnd - iReqCur))) == KErrNone) |
|
2135 { |
|
2136 complete = EFalse; |
|
2137 } |
|
2138 } |
|
2139 // if format finished, write an MBR if required |
|
2140 // Always write an MBR if it's an SD card |
|
2141 else if (iCreateMbr) |
|
2142 { |
|
2143 // Finished Format, so write the MBR/default partition table if required |
|
2144 r = WritePartitionInfo(); |
|
2145 complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse; |
|
2146 } |
|
2147 } |
|
2148 } |
|
2149 break; |
|
2150 |
|
2151 case EMReqPtnInfo: |
|
2152 if (r == KErrNone) |
|
2153 r = DecodePartitionInfo(); // set up iPartitionInfo |
|
2154 |
|
2155 PartitionInfoComplete(r == KErrNone?KErrNone:KErrNotReady); |
|
2156 break; |
|
2157 |
|
2158 case EMReqEMMCPtnInfo: |
|
2159 iMedReq = EMReqIdle; |
|
2160 // For now do nothing.. |
|
2161 break; |
|
2162 |
|
2163 case EMReqUpdatePtnInfo: |
|
2164 break; |
|
2165 |
|
2166 case EMReqPswdCtrl: |
|
2167 if (r == KErrLocked) |
|
2168 r = KErrAccessDenied; |
|
2169 break; |
|
2170 |
|
2171 case EMReqForceErase: |
|
2172 |
|
2173 if (r == KErrNone) |
|
2174 { |
|
2175 // Finished Forced Erase , so write the default partition table... |
|
2176 r = WritePartitionInfo(); |
|
2177 } |
|
2178 |
|
2179 complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse; |
|
2180 break; |
|
2181 |
|
2182 case EMReqWritePasswordData: |
|
2183 // |
|
2184 // WritePasswordData also kicks off an auto-unlock session to ensure that |
|
2185 // any locked cards that have passwords in the password store are immediately |
|
2186 // available. We can safely ignore any errors returned at this stage, as the |
|
2187 // password store will have been successfully updated (in locmedia.cpp), even |
|
2188 // if the card is unable to accept the password. |
|
2189 // |
|
2190 r = KErrNone; |
|
2191 break; |
|
2192 |
|
2193 case EMReqIdle: |
|
2194 // request has been completed already (e.g. due to a power down) |
|
2195 break; |
|
2196 |
|
2197 |
|
2198 default: |
|
2199 __ASSERT_DEBUG(EFalse, Panic(EDSEDRequest)); |
|
2200 break; |
|
2201 } |
|
2202 } |
|
2203 |
|
2204 // r != KErrNone => complete |
|
2205 __ASSERT_DEBUG(!(r != KErrNone) || complete, Panic(EDSEDNotErrComplete)); |
|
2206 |
|
2207 if (complete) |
|
2208 { |
|
2209 if (r != KErrNone) |
|
2210 InvalidateCache(); |
|
2211 |
|
2212 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mdf:dsed:cmp:%d", r)); |
|
2213 CompleteRequest(r); |
|
2214 } |
|
2215 else |
|
2216 { |
|
2217 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mdf:dsed:ncmp")); |
|
2218 } |
|
2219 } |
|
2220 |
|
2221 void DMmcMediaDriverFlash::DataTransferCallBack(TAny* aMediaDriver) |
|
2222 { |
|
2223 DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver); |
|
2224 __ASSERT_DEBUG(! md.iDataTransferCallBackDfc.Queued(), Panic(EDBCBQueued)); |
|
2225 md.iDataTransferCallBackDfc.Enque(); |
|
2226 } |
|
2227 |
|
2228 void DMmcMediaDriverFlash::DataTransferCallBackDfc(TAny* aMediaDriver) |
|
2229 { |
|
2230 DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver); |
|
2231 |
|
2232 if (md.iDoPhysicalAddress) |
|
2233 { |
|
2234 if(md.CurrentRequest() == EMReqWrite) |
|
2235 { |
|
2236 md.DoPhysWriteDataTransferCallBack(); |
|
2237 } |
|
2238 else |
|
2239 { |
|
2240 md.DoPhysReadDataTransferCallBack(); |
|
2241 } |
|
2242 } |
|
2243 else |
|
2244 { |
|
2245 if(md.CurrentRequest() == EMReqWrite) |
|
2246 { |
|
2247 md.DoWriteDataTransferCallBack(); |
|
2248 } |
|
2249 else |
|
2250 { |
|
2251 md.DoReadDataTransferCallBack(); |
|
2252 } |
|
2253 } |
|
2254 } |
|
2255 |
|
2256 void DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack() |
|
2257 { |
|
2258 __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()")); |
|
2259 |
|
2260 TInt err = KErrNone; |
|
2261 |
|
2262 if ( (iRdROB & KIPCSetup) || ((iReqEnd - iPhysEnd) < iBlkLen) ) |
|
2263 { |
|
2264 //IPC to be setup, or partial end block read |
|
2265 iRdROB &= ~KIPCSetup; |
|
2266 |
|
2267 if ((iReqEnd - iPhysEnd) < iBlkLen) |
|
2268 { |
|
2269 iIntBuf = iCacheBuf; |
|
2270 } |
|
2271 else |
|
2272 { |
|
2273 TPtr8 tgt(iMinorBuf, iBlkLen); |
|
2274 err = ReadDataFromUser(tgt, I64LOW(iPhysEnd-iReqStart)); |
|
2275 iIntBuf = iMinorBuf; |
|
2276 } |
|
2277 |
|
2278 iReqCur = iPhysEnd; |
|
2279 iPhysEnd += iBlkLen; |
|
2280 iBufOfset = 0; |
|
2281 iIPCLen = iBlkLen; |
|
2282 |
|
2283 #if !defined(__WINS__) |
|
2284 iSession->MoreDataAvailable( (TInt)(iBlkLen >> KDiskSectorShift), (TUint8*)Epoc::LinearToPhysical((TLinAddr) iIntBuf), err); |
|
2285 #else |
|
2286 iSession->MoreDataAvailable( (TInt)(iBlkLen >> KDiskSectorShift), iIntBuf, err); |
|
2287 #endif |
|
2288 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--iDoPhysicalAddress(KIPCSetup)")); |
|
2289 return; |
|
2290 } |
|
2291 |
|
2292 PrepareNextPhysicalFragment(); |
|
2293 |
|
2294 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()")); |
|
2295 } |
|
2296 |
|
2297 |
|
2298 void DMmcMediaDriverFlash::DoPhysReadDataTransferCallBack() |
|
2299 { |
|
2300 __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoPhysReadTransferCallBack()")); |
|
2301 |
|
2302 TInt err = KErrNone; |
|
2303 |
|
2304 if ((iRdROB & KIPCWrite) && !iSecondBuffer) |
|
2305 { |
|
2306 // an IPC transfer completed |
|
2307 iRdROB &= ~KIPCWrite; |
|
2308 if(iNxtIPCLen) |
|
2309 { |
|
2310 // First transfer is an IPC, |
|
2311 // Corner-case - transfer is most likely IPC-DMA-IPC, |
|
2312 // because write cannot occur until after the first 2 iterations it is possible to arrive here with both IPCSetup & IPCWrite Set. |
|
2313 // need to use iIPCNxtLen instead |
|
2314 TPtrC8 extrView(&iIntBuf[iBufOfset], iNxtIPCLen); |
|
2315 err = iCurrentReq->WriteRemote(&extrView,I64LOW(iReqCur - iReqStart)); |
|
2316 iNxtIPCLen = iBufOfset = 0; |
|
2317 } |
|
2318 else |
|
2319 { |
|
2320 TPtrC8 extrView(&iIntBuf[iBufOfset], iIPCLen); |
|
2321 err = iCurrentReq->WriteRemote(&extrView,I64LOW(iReqCur - iReqStart)); |
|
2322 iIPCLen = iBufOfset = 0; |
|
2323 } |
|
2324 } |
|
2325 |
|
2326 if ( (iRdROB & KIPCSetup) || ((iReqEnd - iPhysEnd) < iBlkLen) ) |
|
2327 { |
|
2328 // IPC to be setup, or partial end block read. |
|
2329 iRdROB &= ~KIPCSetup; |
|
2330 iRdROB |= KIPCWrite; |
|
2331 |
|
2332 iIntBuf = ReserveReadBlocks(iPhysEnd,(iPhysEnd+iBlkLen), &iIPCLen); |
|
2333 |
|
2334 iReqCur = iPhysEnd; |
|
2335 iPhysEnd += iIPCLen; |
|
2336 iBufOfset = 0; |
|
2337 #if !defined(__WINS__) |
|
2338 iSession->MoreDataAvailable( (TInt)(iIPCLen >> KDiskSectorShift), (TUint8*)Epoc::LinearToPhysical((TLinAddr) iIntBuf), err); |
|
2339 #else |
|
2340 iSession->MoreDataAvailable( (TInt)(iIPCLen >> KDiskSectorShift), iIntBuf, err); |
|
2341 #endif |
|
2342 iSecondBuffer = ETrue; |
|
2343 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--iDoPhysicalAddress(KIPCWrite)")); |
|
2344 return; |
|
2345 } |
|
2346 |
|
2347 PrepareNextPhysicalFragment(); |
|
2348 |
|
2349 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoPhysReadTransferCallBack()")); |
|
2350 } |
|
2351 |
|
2352 void DMmcMediaDriverFlash::DoWriteDataTransferCallBack() |
|
2353 { |
|
2354 __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoWriteDataTransferCallBack()")); |
|
2355 |
|
2356 TInt err = KErrNone; |
|
2357 |
|
2358 // Advance current request progress... |
|
2359 iReqCur = iPhysEnd; |
|
2360 |
|
2361 const TUint32 doubleBufferSize = iMaxBufSize >> 1; |
|
2362 |
|
2363 TInt64 length = iDbEnd - iReqCur; |
|
2364 TInt64 medEnd = UMin(iReqCur + doubleBufferSize, iReqCur + length); |
|
2365 |
|
2366 iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk; |
|
2367 TInt64 len = UMin(iDbEnd, iPhysEnd) - iReqCur; |
|
2368 |
|
2369 if(len > doubleBufferSize) |
|
2370 { |
|
2371 // Adjust for maximum size of double-buffering |
|
2372 len = doubleBufferSize; |
|
2373 } |
|
2374 |
|
2375 __ASSERT_DEBUG(len > 0, Panic(EDBLength)); |
|
2376 __ASSERT_DEBUG(I64HIGH((len + (KDiskSectorSize-1)) >> KDiskSectorShift) == 0, Panic(EDBLengthTooBig)); |
|
2377 |
|
2378 TUint32 numBlocks = I64LOW((len + (KDiskSectorSize-1)) >> KDiskSectorShift); |
|
2379 |
|
2380 const TInt64 usrOfst = (iReqCur - iReqStart); |
|
2381 |
|
2382 __ASSERT_DEBUG(I64HIGH(usrOfst) == 0, Panic(EDBOffsetTooBig)); |
|
2383 |
|
2384 // Setup the next buffer pointer and switch buffers... |
|
2385 TUint8* bufPtr = iIntBuf + (iSecondBuffer ? doubleBufferSize : 0); |
|
2386 TPtr8 tgt(bufPtr, I64LOW(len)); |
|
2387 iSecondBuffer = iSecondBuffer ? (TBool)EFalse : (TBool)ETrue; |
|
2388 |
|
2389 if(iDoLastRMW && length < doubleBufferSize) |
|
2390 { |
|
2391 // |
|
2392 // This is the last transfer, and RMW is required. The result of the read exists |
|
2393 // in iMinorBuf, so copy the non-modified section of the block to the active buffer. |
|
2394 // |
|
2395 memcpy(&bufPtr[(numBlocks-1) << KDiskSectorShift], iMinorBuf, KDiskSectorSize); |
|
2396 } |
|
2397 |
|
2398 if(I64LOW(iDbEnd - iReqCur) <= iMaxBufSize) |
|
2399 { |
|
2400 // |
|
2401 // This is the last transfer (with or without RMW) |
|
2402 // - Mark the last blocks as active in the buffer cache. |
|
2403 // |
|
2404 MarkBlocks(iReqCur, iPhysEnd, CchMemToIdx(bufPtr)); |
|
2405 } |
|
2406 |
|
2407 // |
|
2408 // Read the requested data from the remote thread... |
|
2409 // |
|
2410 err = ReadDataFromUser(tgt, I64LOW(usrOfst)); |
|
2411 |
|
2412 // |
|
2413 // ...and signal that data is available to the PSL. |
|
2414 // |
|
2415 iSession->MoreDataAvailable(numBlocks, bufPtr, err); |
|
2416 |
|
2417 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoWriteDataTransferCallBack()")); |
|
2418 } |
|
2419 |
|
2420 |
|
2421 void DMmcMediaDriverFlash::DoReadDataTransferCallBack() |
|
2422 { |
|
2423 __KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoReadTransferCallBack()")); |
|
2424 |
|
2425 TInt err = KErrNone; |
|
2426 |
|
2427 const TUint32 doubleBufferSize = iMaxBufSize >> 1; |
|
2428 |
|
2429 TUint32 bufOfst = 0; |
|
2430 |
|
2431 if((iReqCur & ~iBlkMsk) == iPhysStart) |
|
2432 { |
|
2433 if(iSecondBuffer) |
|
2434 { |
|
2435 // |
|
2436 // If this is the first callback, don't copy data as it's not available yet |
|
2437 // - just drop through to set up the next buffer. |
|
2438 // |
|
2439 TUint32 numBlocks = I64LOW((doubleBufferSize + (KDiskSectorSize-1)) >> KDiskSectorShift); |
|
2440 TUint8* bufPtr = iIntBuf + doubleBufferSize; |
|
2441 |
|
2442 iSecondBuffer = EFalse; |
|
2443 |
|
2444 iSession->MoreDataAvailable(numBlocks, bufPtr, KErrNone); |
|
2445 return; |
|
2446 } |
|
2447 else |
|
2448 { |
|
2449 // |
|
2450 // If this is the second callback we're ready to copy |
|
2451 // back to the client - data may be mis-aligned in the first |
|
2452 // instance, but all subsequent data will be aligned... |
|
2453 // |
|
2454 bufOfst = I64LOW(iReqCur - iPhysStart); |
|
2455 } |
|
2456 } |
|
2457 |
|
2458 // ...otherwise, write the previous buffer contents to the user |
|
2459 TUint8* bufPtr = iIntBuf + (iSecondBuffer ? doubleBufferSize : 0); |
|
2460 |
|
2461 err = WriteDataToUser(bufPtr + bufOfst); |
|
2462 |
|
2463 // Advance current request progress... |
|
2464 iReqCur = iPhysEnd; |
|
2465 |
|
2466 TInt64 medEnd = UMin(iReqCur + doubleBufferSize, iDbEnd); |
|
2467 |
|
2468 iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk; |
|
2469 |
|
2470 // Current buffer is one step ahead of the current request progress... |
|
2471 TInt64 len = UMin((iDbEnd - iPhysEnd + iBlkMsk) & ~iBlkMsk, TInt64(doubleBufferSize)); |
|
2472 |
|
2473 __ASSERT_DEBUG(len == 0 || (I64HIGH((len + (KDiskSectorSize-1)) >> KDiskSectorShift) == 0), Panic(EDBLengthTooBig)); |
|
2474 |
|
2475 TUint32 numBlocks = I64LOW((len + (KDiskSectorSize-1)) >> KDiskSectorShift); |
|
2476 |
|
2477 // |
|
2478 // ...switch buffers and signal that data is available to the PSL. |
|
2479 // |
|
2480 iSecondBuffer = iSecondBuffer ? (TBool)EFalse : (TBool)ETrue; |
|
2481 |
|
2482 iSession->MoreDataAvailable(numBlocks, bufPtr, err); |
|
2483 |
|
2484 __KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoDataTransferCallBack()")); |
|
2485 } |
|
2486 |
|
2487 |
|
2488 // ---- request management ---- |
|
2489 |
|
2490 |
|
2491 TInt DMmcMediaDriverFlash::EngageAndSetReadRequest(DMmcMediaDriverFlash::TMediaRequest aRequest) |
|
2492 { |
|
2493 return EngageAndSetRequest(aRequest, iReadCurrentInMilliAmps); |
|
2494 } |
|
2495 |
|
2496 |
|
2497 TInt DMmcMediaDriverFlash::EngageAndSetWriteRequest(DMmcMediaDriverFlash::TMediaRequest aRequest) |
|
2498 { |
|
2499 return EngageAndSetRequest(aRequest, iWriteCurrentInMilliAmps); |
|
2500 } |
|
2501 |
|
2502 |
|
2503 TInt DMmcMediaDriverFlash::EngageAndSetRequest(DMmcMediaDriverFlash::TMediaRequest aRequest, TInt aCurrent) |
|
2504 // |
|
2505 // In WINS, all of the processing, including the callbacks, is done when Engage() is called, |
|
2506 // so the request value must be set up in advanced. Both the request and the current are |
|
2507 // cleared in the corresponding call to CompleteRequest(). |
|
2508 // |
|
2509 { |
|
2510 __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); |
|
2511 |
|
2512 iMedReq = aRequest; |
|
2513 SetCurrentConsumption(aCurrent); |
|
2514 |
|
2515 TInt r = InCritical(); |
|
2516 if (r == KErrNone) |
|
2517 { |
|
2518 r = iSession->Engage(); |
|
2519 } |
|
2520 |
|
2521 if(r != KErrNone) |
|
2522 { |
|
2523 if (!Kern::PowerGood()) |
|
2524 r=KErrAbort; // If emergency power down - return abort rather than anything else. |
|
2525 if (!iCard->IsReady()) |
|
2526 r=KErrNotReady; // If media change - return not ready rather than anything else. |
|
2527 EndInCritical(); |
|
2528 } |
|
2529 |
|
2530 return r; |
|
2531 } |
|
2532 |
|
2533 |
|
2534 void DMmcMediaDriverFlash::CompleteRequest(TInt aReason) |
|
2535 // |
|
2536 // completes the specified request |
|
2537 // |
|
2538 { |
|
2539 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:cr0x%08x,%d", iCurrentReq, aReason)); |
|
2540 |
|
2541 iMedReq = EMReqIdle; |
|
2542 SetCurrentConsumption(KIdleCurrentInMilliAmps); |
|
2543 |
|
2544 TLocDrvRequest* pR=iCurrentReq; |
|
2545 if (pR) |
|
2546 { |
|
2547 #ifdef __DEMAND_PAGING__ |
|
2548 #if defined(__TEST_PAGING_MEDIA_DRIVER__) |
|
2549 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Complete req Id(%d) with(%d)", pR->Id(), aReason)); |
|
2550 #endif // __TEST_PAGING_MEDIA_DRIVER__ |
|
2551 #endif // __DEMAND_PAGING__ |
|
2552 iCurrentReq=NULL; |
|
2553 DMediaDriver::Complete(*pR,aReason); |
|
2554 } |
|
2555 } |
|
2556 |
|
2557 TInt DMmcMediaDriverFlash::Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo) |
|
2558 { |
|
2559 // Fill buffer with current media caps. |
|
2560 aInfo.iType = EMediaHardDisk; |
|
2561 aInfo.iBattery = EBatNotSupported; |
|
2562 aInfo.iDriveAtt = KDriveAttLocal; |
|
2563 aInfo.iMediaAtt = KMediaAttFormattable; |
|
2564 |
|
2565 if(iCard->iFlags & KMMCardIsLockable) |
|
2566 aInfo.iMediaAtt |= KMediaAttLockable; |
|
2567 |
|
2568 if (iCard->HasPassword()) |
|
2569 aInfo.iMediaAtt |= KMediaAttHasPassword; |
|
2570 if (iCard->IsWriteProtected()) |
|
2571 aInfo.iMediaAtt |= KMediaAttWriteProtected; |
|
2572 if (iCard->IsLocked()) |
|
2573 aInfo.iMediaAtt |= KMediaAttLocked; |
|
2574 |
|
2575 aInfo.iFileSystemId = KDriveFileSysFAT; |
|
2576 |
|
2577 // Format is performed in multiples of the erase sector (or multiple block) size |
|
2578 aInfo.iMaxBytesPerFormat = iEraseInfo.iPreferredEraseUnitSize; |
|
2579 |
|
2580 if ((!iInternalSlot) && (GetCardFormatInfo(iCard,aInfo.iFormatInfo) == KErrNone)) |
|
2581 { |
|
2582 TUint16 reservedSectors; |
|
2583 TMBRPartitionEntry dummy; // Not used here |
|
2584 const TInt r = GetMediaDefaultPartitionInfo(dummy, reservedSectors, iCard); |
|
2585 if(r != KErrNone) |
|
2586 return r; |
|
2587 |
|
2588 aInfo.iFormatInfo.iReservedSectors = reservedSectors; |
|
2589 aInfo.iExtraInfo = ETrue; |
|
2590 } |
|
2591 |
|
2592 // Set serial number to CID |
|
2593 __ASSERT_DEBUG(KMMCCIDLength<=KMaxSerialNumLength, Kern::PanicCurrentThread(_L("Mmc"), KErrOverflow)); |
|
2594 aInfo.iSerialNumLength = KMMCCIDLength; |
|
2595 for (TUint i=0; i<KMMCCIDLength; i++) |
|
2596 aInfo.iSerialNum[i] = iCard->CID().At(i); |
|
2597 |
|
2598 // Get block size & erase block size to allow the file system to align first usable cluster correctly |
|
2599 aInfo.iBlockSize = BlockSize(iCard); |
|
2600 aInfo.iEraseBlockSize = EraseBlockSize(iCard); |
|
2601 |
|
2602 #if defined(__DEMAND_PAGING__) |
|
2603 // If the stack has flagged this as a demand-paging device, then it is assumed that it is internal |
|
2604 // and (optionally) write protected. |
|
2605 if(aDrive.iPrimaryMedia->iPagingMedia) |
|
2606 { |
|
2607 aInfo.iMediaAtt|= KMediaAttPageable; |
|
2608 if (iDemandPagingInfo.iWriteProtected) |
|
2609 { |
|
2610 aInfo.iMediaAtt|= KMediaAttWriteProtected; |
|
2611 aInfo.iMediaAtt&= ~KMediaAttFormattable; |
|
2612 } |
|
2613 } |
|
2614 |
|
2615 // code paging enabled on this drive ? |
|
2616 if(aDrive.iPagingDrv) |
|
2617 { |
|
2618 aInfo.iDriveAtt|= KDriveAttPageable; |
|
2619 } |
|
2620 |
|
2621 #endif |
|
2622 |
|
2623 if (iInternalSlot) |
|
2624 { |
|
2625 aInfo.iDriveAtt|= KDriveAttInternal; |
|
2626 } |
|
2627 else |
|
2628 { |
|
2629 aInfo.iDriveAtt|= KDriveAttRemovable; |
|
2630 } |
|
2631 |
|
2632 |
|
2633 if (iMmcPartitionInfo) |
|
2634 { |
|
2635 TLocalDriveCapsV6Buf CapsInfo = aInfo; |
|
2636 iMmcPartitionInfo->PartitionCaps(aDrive,CapsInfo); |
|
2637 aInfo = CapsInfo(); |
|
2638 } |
|
2639 |
|
2640 |
|
2641 if (iMediaType==EMultiMediaROM) |
|
2642 { |
|
2643 aInfo.iMediaAtt|= KMediaAttWriteProtected; |
|
2644 aInfo.iMediaAtt&= ~KMediaAttFormattable; |
|
2645 } |
|
2646 |
|
2647 // Must return KErrCompletion to indicate that this |
|
2648 // is a synchronous version of the function |
|
2649 return KErrCompletion; |
|
2650 } |
|
2651 |
|
2652 |
|
2653 // ---- cache ---- |
|
2654 |
|
2655 TInt DMmcMediaDriverFlash::ReadDataUntilCacheExhausted(TBool* aAllDone) |
|
2656 // |
|
2657 // scans the cache for blocks corresponding to the range iReqCur to iReqEnd and |
|
2658 // writes them to user memory. Starts at iReqCur & ~iBlkMsk and looks for blocks |
|
2659 // at sequential media positions. Completes when a block is not available, even |
|
2660 // if a following block is available in the cache. *aAllDone is undefined if the |
|
2661 // return value is not KErrNone. |
|
2662 // |
|
2663 // This function is linear in the number of blocks in the cache. |
|
2664 // |
|
2665 { |
|
2666 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rdc:%x,%x", iReqCur, iReqEnd)); |
|
2667 |
|
2668 #if defined(__DEMAND_PAGING__) && !defined(__WINS__) |
|
2669 if (DMediaPagingDevice::PageInRequest(*iCurrentReq)) |
|
2670 { |
|
2671 *aAllDone = EFalse; |
|
2672 return KErrNone; |
|
2673 } |
|
2674 #endif //DEMAND_PAGING |
|
2675 |
|
2676 TInt64 physStart = iReqCur & ~iBlkMsk; |
|
2677 TInt64 physEnd = Min(physStart + iMaxBufSize, (iReqEnd + iBlkMsk) & ~iBlkMsk); |
|
2678 BuildGammaArray(physStart, physEnd); |
|
2679 |
|
2680 TInt r = KErrNone; |
|
2681 TInt curBlk = 0; |
|
2682 TInt cchBlk; |
|
2683 while ( |
|
2684 r == KErrNone |
|
2685 && physStart + (curBlk << iBlkLenLog2) < physEnd |
|
2686 && (cchBlk = iGamma[curBlk]) != KNoCacheBlock ) |
|
2687 { |
|
2688 // set up instance variables for WriteDataToUser() |
|
2689 iPhysStart = physStart + (curBlk << iBlkLenLog2); |
|
2690 iPhysEnd = iPhysStart + iBlkLen; |
|
2691 iIntBuf = IdxToCchMem(cchBlk); |
|
2692 |
|
2693 if ((r = WriteDataToUser(&iIntBuf[I64LOW(iReqCur - iPhysStart)])) == KErrNone) |
|
2694 { |
|
2695 iReqCur = iPhysEnd; |
|
2696 iLstUsdCchEnt = iGamma[curBlk]; |
|
2697 ++curBlk; |
|
2698 } |
|
2699 } |
|
2700 |
|
2701 *aAllDone = (iReqCur >= iReqEnd); |
|
2702 |
|
2703 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rdc:%d,%d", *aAllDone, r)); |
|
2704 return r; |
|
2705 } |
|
2706 |
|
2707 |
|
2708 TInt DMmcMediaDriverFlash::WriteDataToUser(TUint8* aBufPtr) |
|
2709 // |
|
2710 // write the data from the most recent read operation to the user descriptor |
|
2711 // |
|
2712 { |
|
2713 TInt r = KErrNotSupported; |
|
2714 |
|
2715 // get range of data to read out of internal buffer |
|
2716 |
|
2717 TInt len = I64LOW(UMin(iPhysEnd, iReqEnd) - iReqCur); |
|
2718 TPtrC8 extrView(aBufPtr, len); |
|
2719 |
|
2720 // write data from internal buffer |
|
2721 TUint usrOfst = I64LOW(iReqCur - iReqStart); |
|
2722 |
|
2723 #if defined(__DEMAND_PAGING__) && !defined(__WINS__) |
|
2724 if (DMediaPagingDevice::PageInRequest(*iCurrentReq)) |
|
2725 r=iCurrentReq->WriteToPageHandler((TUint8 *)(&extrView[0]), len, usrOfst); |
|
2726 else |
|
2727 #endif // __DEMAND_PAGING__ |
|
2728 r = iCurrentReq->WriteRemote(&extrView,usrOfst); |
|
2729 |
|
2730 return r; |
|
2731 } |
|
2732 |
|
2733 TInt DMmcMediaDriverFlash::ReadDataFromUser(TDes8& aDes, TInt aOffset) |
|
2734 { |
|
2735 #ifndef __WINS__ |
|
2736 if (DMediaPagingDevice::PageOutRequest(*iCurrentReq)) |
|
2737 return iCurrentReq->ReadFromPageHandler((TAny*) aDes.Ptr(), aDes.MaxLength(), aOffset); |
|
2738 else |
|
2739 #endif // #ifndef __WINS__ |
|
2740 return iCurrentReq->ReadRemote(&aDes, aOffset); |
|
2741 } |
|
2742 |
|
2743 TInt DMmcMediaDriverFlash::AdjustPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength) |
|
2744 // |
|
2745 // Retrieve next Physical memory fragment and adjust the start pointer and length with |
|
2746 // respect to the set offset {iFragOfset}. |
|
2747 // Note the offset may encompass multiple memory fragments. |
|
2748 // |
|
2749 { |
|
2750 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:APF")); |
|
2751 |
|
2752 TInt err = KErrNone; |
|
2753 TInt offset = iFragOfset; |
|
2754 |
|
2755 do |
|
2756 { |
|
2757 err = iCurrentReq->GetNextPhysicalAddress(aPhysAddr, aPhysLength); |
|
2758 |
|
2759 if (err != KErrNone) |
|
2760 return err; |
|
2761 |
|
2762 if (offset >= aPhysLength) // more offset than in this physical chunk |
|
2763 { |
|
2764 offset -= aPhysLength; |
|
2765 } |
|
2766 else |
|
2767 { |
|
2768 // offset < physLength |
|
2769 // offset lies within the memory chunk |
|
2770 // Adjust length and address for first transfer |
|
2771 aPhysLength -= offset; |
|
2772 aPhysAddr += offset; |
|
2773 offset = -1; |
|
2774 } |
|
2775 |
|
2776 } while (offset >= 0); |
|
2777 |
|
2778 iFragOfset = 0; // reset offset now complete |
|
2779 |
|
2780 if (aPhysAddr == 0) |
|
2781 { |
|
2782 return KErrNoMemory; |
|
2783 } |
|
2784 |
|
2785 #ifdef _DEBUG |
|
2786 // DMAHelper ensures memory is dma aligned |
|
2787 if ( (aPhysAddr & (iSocket->DmaAlignment()-1) ) ) |
|
2788 { |
|
2789 __KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lr:Memory Fragment Not Word Aligned!")); |
|
2790 Panic(ENotDMAAligned); |
|
2791 } |
|
2792 #endif //_DEBUG |
|
2793 |
|
2794 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:APF physAddr(0x%x), physLength(%d)",aPhysAddr, aPhysLength)); |
|
2795 return err; |
|
2796 } |
|
2797 |
|
2798 TInt DMmcMediaDriverFlash::PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength) |
|
2799 // |
|
2800 // Retrieves the first Physical memory fragment and determines the type of the next transfer |
|
2801 // Next transfer may either be the last block (end not block aligned) or a block may straddle |
|
2802 // memory fragments. |
|
2803 // |
|
2804 { |
|
2805 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF")); |
|
2806 TInt r = KErrNone; |
|
2807 |
|
2808 r = AdjustPhysicalFragment(aPhysAddr, aPhysLength); |
|
2809 |
|
2810 if (r == KErrNone) |
|
2811 { |
|
2812 TUint len = I64LOW(iReqEnd & iBlkMsk); |
|
2813 if ( ((TUint32)aPhysLength >= aLength) && len ) |
|
2814 { |
|
2815 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF-end block")); |
|
2816 //next iteration will be an IPC for the end block |
|
2817 //There is enough space in physical memory to fit |
|
2818 //the extended read, but exceeds boundary for this request. |
|
2819 iIPCLen = len; |
|
2820 iRdROB |= KIPCSetup; // IPC setup for next iteration |
|
2821 aPhysLength -= len; |
|
2822 } |
|
2823 |
|
2824 if (aPhysLength & iBlkMsk) |
|
2825 { |
|
2826 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF-straddles boundary")); |
|
2827 // block must be straddling a fragment boundary |
|
2828 // Next iteration must be an IPC |
|
2829 iRdROB |= KIPCSetup; |
|
2830 |
|
2831 // Calculate the offset into the next memory block |
|
2832 iFragOfset = I64LOW(iBlkLen - (aPhysLength & iBlkMsk)); |
|
2833 aPhysLength &= ~iBlkMsk; |
|
2834 } |
|
2835 } |
|
2836 |
|
2837 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:PFPF err(%d), physAddr(0x%x), physLength(%d)",r, aPhysAddr, aPhysLength)); |
|
2838 return r; |
|
2839 } |
|
2840 |
|
2841 |
|
2842 void DMmcMediaDriverFlash::PrepareNextPhysicalFragment() |
|
2843 // |
|
2844 // Retrieves next Physical memory fragment and determines the type of the next transfer |
|
2845 // Next transfer may either be the last block (end not block aligned) or a block may straddle |
|
2846 // memory fragments. |
|
2847 // |
|
2848 { |
|
2849 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF")); |
|
2850 TInt err = KErrNone; |
|
2851 TPhysAddr physAddr = 0; |
|
2852 TInt physLength = 0; |
|
2853 |
|
2854 err = AdjustPhysicalFragment(physAddr, physLength); |
|
2855 |
|
2856 if (err == KErrNone) |
|
2857 { |
|
2858 if (iPhysEnd+physLength >= iReqEnd) |
|
2859 { |
|
2860 //Last physical transfer ... |
|
2861 TUint len = I64LOW(iReqEnd & iBlkMsk); |
|
2862 if (len) |
|
2863 { |
|
2864 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF-end block")); |
|
2865 // end point not block aligned! |
|
2866 // next iteration must be an IPC call |
|
2867 iRdROB |= KIPCSetup; |
|
2868 iIPCLen = len; |
|
2869 physLength -= len; |
|
2870 } |
|
2871 else{ |
|
2872 physLength = I64LOW(iDbEnd - iPhysEnd); |
|
2873 } |
|
2874 } |
|
2875 |
|
2876 if (physLength & iBlkMsk) |
|
2877 { |
|
2878 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF-straddles boundary")); |
|
2879 // block must be straddling a fragment boundary |
|
2880 // Next iteration must be an IPC |
|
2881 iRdROB |= KIPCSetup; |
|
2882 |
|
2883 // Calculate the offset into the next memory block |
|
2884 iFragOfset = I64LOW(iBlkLen - (physLength & iBlkMsk)); |
|
2885 physLength &= ~iBlkMsk; |
|
2886 } |
|
2887 |
|
2888 iPhysEnd += physLength; |
|
2889 } |
|
2890 |
|
2891 iSession->MoreDataAvailable( (physLength >> KDiskSectorShift), (TUint8*) physAddr, err); |
|
2892 iSecondBuffer = EFalse; |
|
2893 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:PNPF")); |
|
2894 } |
|
2895 |
|
2896 TUint8* DMmcMediaDriverFlash::ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength) |
|
2897 // |
|
2898 // Assume the cache has been drained before this function is called and so |
|
2899 // the first block is not in the cache. The length of the allocated range is |
|
2900 // either aEnd - aStart, or enough blocks such that the next block to read |
|
2901 // is already available in the cache, and so will be read when |
|
2902 // ReadDataUntilCacheExhausted() is called from the callback DFC. |
|
2903 // |
|
2904 { |
|
2905 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rrb:%lx,%lx", aStart, aEnd)); |
|
2906 |
|
2907 __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(ERRBStAlign)); |
|
2908 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ERRBStPos)); |
|
2909 __ASSERT_DEBUG(aEnd > aStart, Panic(ERRBNotPositive)); |
|
2910 __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(ERRBEndAlign)); |
|
2911 __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(ERRBEndPos)); |
|
2912 __ASSERT_DEBUG(!iDoDoubleBuffer, Panic(ENoDBSupport)); |
|
2913 __ASSERT_CACHE(CacheInvariant(), Panic(ERRBCchInv)); |
|
2914 __ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ERRBExist)); |
|
2915 |
|
2916 TUint8* raby; |
|
2917 |
|
2918 BuildGammaArray(aStart, aEnd); |
|
2919 |
|
2920 // reposition start index at 0 if the full range would run off the end of the |
|
2921 // buffer. This is heuristic - enabling a longer multi-block may cost some |
|
2922 // cached reads. However, assume long reads do not generally re-read the same |
|
2923 // data, and are used for streaming large amounts of data into memory. |
|
2924 |
|
2925 const TInt blocksInRange = I64LOW((aEnd - aStart) >> iBlkLenLog2); |
|
2926 TInt startIndex = (iLstUsdCchEnt + 1) % iBlocksInBuffer; |
|
2927 if (startIndex + blocksInRange > iBlocksInBuffer) |
|
2928 startIndex = 0; |
|
2929 |
|
2930 // starting at startIndex, increase the range until it covers aEnd - aStart, |
|
2931 // or until the next block to read is available in the cache. |
|
2932 |
|
2933 TInt blkCnt = 0; |
|
2934 TBool finished; |
|
2935 do |
|
2936 { |
|
2937 finished = ( |
|
2938 // range allocated for entire read |
|
2939 blkCnt == blocksInRange |
|
2940 // next block already exists in buffer and has not been overwritten |
|
2941 // by existing multi-block read |
|
2942 || ( iGamma[blkCnt] != KNoCacheBlock |
|
2943 && ( iGamma[blkCnt] < startIndex |
|
2944 || iGamma[blkCnt] >= startIndex + blkCnt ) ) ); |
|
2945 |
|
2946 if (! finished) |
|
2947 ++blkCnt; |
|
2948 } while (! finished); |
|
2949 |
|
2950 iLstUsdCchEnt = startIndex + blkCnt - 1; |
|
2951 |
|
2952 if (blkCnt < 1) blkCnt = 1; //RBW required < 1 block to be read |
|
2953 |
|
2954 TUint32 lengthInBytes = blkCnt << iBlkLenLog2; |
|
2955 *aLength = lengthInBytes; |
|
2956 MarkBlocks(aStart, aStart + lengthInBytes, startIndex); |
|
2957 |
|
2958 raby = IdxToCchMem(startIndex); |
|
2959 |
|
2960 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rrb:%x", (TUint32) raby)); |
|
2961 |
|
2962 return raby; |
|
2963 } |
|
2964 |
|
2965 |
|
2966 TUint8* DMmcMediaDriverFlash::ReserveWriteBlocks(TInt64 aStart, TInt64 aEnd, TUint* aRBM) |
|
2967 // |
|
2968 // reserve a range of blocks in the buffer. If the block containing aStart or aEnd |
|
2969 // are already in the buffer, attempts to position on them. This can save one or two |
|
2970 // RBMs for writes. |
|
2971 // |
|
2972 // This function is linear in the number of blocks - it runs through the array |
|
2973 // exactly twice. |
|
2974 // |
|
2975 // aStart and aEnd are not necessarily block aligned - the function uses alignment |
|
2976 // information to minimize RBMs. |
|
2977 // |
|
2978 { |
|
2979 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rwb:%lx,%lx", aStart, aEnd)); |
|
2980 |
|
2981 TInt64 physStart = aStart & ~iBlkMsk; |
|
2982 TInt64 physEnd = (aEnd + iBlkMsk) & ~iBlkMsk; |
|
2983 |
|
2984 __ASSERT_DEBUG(TotalSizeInBytes() > physStart, Panic(ERWBStPos)); |
|
2985 __ASSERT_DEBUG(aEnd > aStart, Panic(ERWBNotPositive)); |
|
2986 __ASSERT_DEBUG(TotalSizeInBytes() >= physEnd, Panic(ERWBEndPos)); |
|
2987 __ASSERT_DEBUG(iDoPhysicalAddress || iDoDoubleBuffer || (!iDoDoubleBuffer && !iDoPhysicalAddress && physEnd - physStart <= (TInt64)iMaxBufSize), Panic(ERWBOverflow)); |
|
2988 __ASSERT_CACHE(CacheInvariant(), Panic(ERWBCchInv)); |
|
2989 |
|
2990 const TBool firstPartial = (aStart & iBlkMsk) != 0; |
|
2991 const TBool lastPartial = (aEnd & iBlkMsk) != 0; |
|
2992 |
|
2993 const TInt blkCnt = I64LOW((physEnd - physStart) >> iBlkLenLog2); |
|
2994 |
|
2995 TBool startUsed = EFalse; |
|
2996 TBool endUsed = EFalse; |
|
2997 |
|
2998 TUint8* raby = NULL; |
|
2999 |
|
3000 if(iDoDoubleBuffer) |
|
3001 { |
|
3002 // |
|
3003 // If we're double-buffering, then the entire cache will be re-used |
|
3004 // continuously. Rather than continually reserve blocks during each |
|
3005 // transfer we calculate the blocks that will be present after all |
|
3006 // transfers have completed. |
|
3007 // |
|
3008 InvalidateCache(); |
|
3009 raby = iCacheBuf; |
|
3010 } |
|
3011 else |
|
3012 { |
|
3013 TInt idx; |
|
3014 |
|
3015 // check if the first or last blocks are already in the buffer. |
|
3016 TInt fst = -1, lst = -1; |
|
3017 const TInt64 lstBlk = physEnd - iBlkLen; |
|
3018 TInt i; |
|
3019 for (i = 0; i < iBlocksInBuffer; ++i) |
|
3020 { |
|
3021 if (iCachedBlocks[i] == physStart) |
|
3022 fst = i; |
|
3023 |
|
3024 if (iCachedBlocks[i] == lstBlk) |
|
3025 lst = i; |
|
3026 } |
|
3027 |
|
3028 const TBool firstUsable = (fst != -1) && (iBlocksInBuffer - fst) >= blkCnt; |
|
3029 const TBool lastUsable = (lst != -1) && lst >= (blkCnt - 1); |
|
3030 |
|
3031 if (iDoPhysicalAddress) |
|
3032 { |
|
3033 if ( (firstPartial || lastPartial) && blkCnt <= 2) |
|
3034 { |
|
3035 //Physical addressing not to be used. |
|
3036 //more efficent to use local Cache copying |
|
3037 iDoPhysicalAddress = EFalse; |
|
3038 return raby; |
|
3039 } |
|
3040 else |
|
3041 { |
|
3042 raby = iMinorBuf; |
|
3043 |
|
3044 const TBool firstPres = (fst != -1); |
|
3045 const TBool lastPres = (lst != -1); |
|
3046 |
|
3047 if (firstPartial && firstPres) |
|
3048 { |
|
3049 // move to minor buffer |
|
3050 memcpy(iMinorBuf, IdxToCchMem(fst), iBlkLen); |
|
3051 } |
|
3052 if (lastPartial && lastPres) |
|
3053 { |
|
3054 // move to beginning of cache |
|
3055 memcpy(iCacheBuf, IdxToCchMem(lst), iBlkLen); |
|
3056 } |
|
3057 |
|
3058 InvalidateCache(physStart,physEnd); |
|
3059 |
|
3060 if (lastPartial) |
|
3061 { |
|
3062 //re-mark beginning of cache |
|
3063 MarkBlocks((physEnd-iBlkLen), physEnd, 0); |
|
3064 } |
|
3065 |
|
3066 if (aRBM) |
|
3067 { |
|
3068 *aRBM = 0; |
|
3069 |
|
3070 if (firstPartial) |
|
3071 *aRBM |= KWtMinFst; |
|
3072 |
|
3073 if (firstPartial && !firstPres) |
|
3074 *aRBM |= KWtRBMFst; |
|
3075 |
|
3076 if (lastPartial) |
|
3077 *aRBM |= KWtMinLst; |
|
3078 |
|
3079 if (lastPartial && !lastPres) |
|
3080 *aRBM |= KWtRBMLst; |
|
3081 } |
|
3082 |
|
3083 return raby; |
|
3084 } |
|
3085 } // if (iDoPhysicalAddress) |
|
3086 |
|
3087 if (!firstUsable && !lastUsable) |
|
3088 { |
|
3089 if(iDoDoubleBuffer) |
|
3090 { |
|
3091 idx = iSecondBuffer ? iBlocksInBuffer >> 1 : 0; |
|
3092 } |
|
3093 else |
|
3094 { |
|
3095 idx = (iLstUsdCchEnt + 1) % iBlocksInBuffer; |
|
3096 if (idx + blkCnt > iBlocksInBuffer) |
|
3097 idx = 0; |
|
3098 } |
|
3099 } |
|
3100 else if (firstUsable && ! lastUsable) |
|
3101 { |
|
3102 idx = fst; |
|
3103 } |
|
3104 else if (! firstUsable && lastUsable) |
|
3105 { |
|
3106 idx = lst - (blkCnt - 1); |
|
3107 } |
|
3108 else // (lastUsable && firstUsable) |
|
3109 { |
|
3110 if (firstPartial || ! lastPartial) |
|
3111 idx = fst; |
|
3112 else |
|
3113 idx = lst - (blkCnt - 1); |
|
3114 } |
|
3115 |
|
3116 MarkBlocks(physStart, physEnd, idx); |
|
3117 |
|
3118 // if the range started or ended on a partial block, but could not |
|
3119 // be allocated on that existing block, and the existing block is |
|
3120 // somewhere in the cache, then memcpy() that block to the end of the |
|
3121 // range. used is not the same as usable - both the start and end |
|
3122 // blocks may be usable, through not in the same range, or any range. |
|
3123 |
|
3124 const TInt startExtent = I64LOW(aStart & iBlkMsk); |
|
3125 TBool firstInTemp = EFalse; |
|
3126 startUsed = (idx == fst); |
|
3127 if (! startUsed && firstPartial && fst != -1) |
|
3128 { |
|
3129 // if the range has started at index occupied by the last block then |
|
3130 // temporarily copy to minor buffer. This is unnecessary when the |
|
3131 // last block is not partial because the last block does not need to |
|
3132 // be preserved. |
|
3133 |
|
3134 if (idx == lst && lastPartial) |
|
3135 { |
|
3136 firstInTemp = ETrue; |
|
3137 memcpy(iMinorBuf, IdxToCchMem(fst), startExtent); |
|
3138 } |
|
3139 else |
|
3140 { |
|
3141 memcpy(IdxToCchMem(idx), IdxToCchMem(fst), startExtent); |
|
3142 } |
|
3143 |
|
3144 startUsed = ETrue; |
|
3145 } |
|
3146 |
|
3147 endUsed = (idx + blkCnt - 1 == lst); |
|
3148 if (! endUsed && lastPartial && lst != -1) |
|
3149 { |
|
3150 const TInt endOffset = I64LOW(aEnd & iBlkMsk); |
|
3151 const TInt endExtent = iBlkLen - endOffset; |
|
3152 memcpy(IdxToCchMem(idx + blkCnt - 1) + endOffset, IdxToCchMem(lst) + endOffset, endExtent); |
|
3153 endUsed = ETrue; |
|
3154 } |
|
3155 |
|
3156 if (firstInTemp) |
|
3157 memcpy(IdxToCchMem(idx), iMinorBuf, startExtent); |
|
3158 |
|
3159 // start reclaiming at block following this range |
|
3160 iLstUsdCchEnt = idx + blkCnt - 1; |
|
3161 raby = IdxToCchMem(idx); |
|
3162 } |
|
3163 |
|
3164 // work out if read-before-write required |
|
3165 if (aRBM) |
|
3166 { |
|
3167 *aRBM = 0; |
|
3168 // first index was not already in range, and does not start on block boundary |
|
3169 if (firstPartial && ! startUsed) |
|
3170 *aRBM |= KWtRBMFst; |
|
3171 |
|
3172 // last index was not already in range, and does not end on block boundary |
|
3173 if (lastPartial && ! endUsed) |
|
3174 *aRBM |= KWtRBMLst; |
|
3175 |
|
3176 // only use one pre-read if contained in single block |
|
3177 if (blkCnt == 1 && *aRBM == (KWtRBMFst | KWtRBMLst)) |
|
3178 *aRBM = KWtRBMFst; |
|
3179 |
|
3180 // |
|
3181 // When double-buffering, RMW for the last block is stored in the |
|
3182 // minor buffer and writen during the last transfer, so flag this |
|
3183 // seperately (as aRBM is used for the initial RMW Read then subsequently cleared). |
|
3184 // |
|
3185 if(iDoDoubleBuffer && (*aRBM & KWtRBMLst)) |
|
3186 iDoLastRMW = ETrue; |
|
3187 } |
|
3188 |
|
3189 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rwb:%x", (TUint32) raby)); |
|
3190 |
|
3191 return raby; |
|
3192 } |
|
3193 |
|
3194 void DMmcMediaDriverFlash::MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex) |
|
3195 // |
|
3196 // mark range of blocks for media range. If existing cache entries for any part of |
|
3197 // the cache are already in the buffer they are invalidated. |
|
3198 // |
|
3199 { |
|
3200 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:mb:%lx,%lx,%d", aStart, aEnd, aStartIndex)); |
|
3201 |
|
3202 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EMBStPos)); |
|
3203 __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(EMBStAlign)); |
|
3204 __ASSERT_DEBUG(aEnd > aStart, Panic(EMBNotPositive)); |
|
3205 __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EMBEndPos)); |
|
3206 __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(EMBEndAlign)); |
|
3207 __ASSERT_DEBUG(aStartIndex + (TInt)((aEnd - aStart) >> iBlkLenLog2) <= iBlocksInBuffer, Panic(EMBOverflow)); |
|
3208 __ASSERT_CACHE(CacheInvariant(), Panic(EMBCchInvPre)); |
|
3209 |
|
3210 TInt i; |
|
3211 |
|
3212 for (i = 0; i < aStartIndex; ++i) |
|
3213 { |
|
3214 if (iCachedBlocks[i] >= aStart && iCachedBlocks[i] < aEnd) |
|
3215 iCachedBlocks[i] = KInvalidBlock; |
|
3216 } |
|
3217 |
|
3218 TInt blkCnt = I64LOW((aEnd - aStart) >> iBlkLenLog2); |
|
3219 for (i = aStartIndex; i < aStartIndex + blkCnt; ++i) |
|
3220 iCachedBlocks[i] = aStart + (static_cast<TUint32>(i - aStartIndex) << iBlkLenLog2); |
|
3221 |
|
3222 for (i = aStartIndex + blkCnt; i < iBlocksInBuffer; ++i) |
|
3223 { |
|
3224 if (iCachedBlocks[i] >= aStart && iCachedBlocks[i] < aEnd) |
|
3225 iCachedBlocks[i] = KInvalidBlock; |
|
3226 } |
|
3227 |
|
3228 __ASSERT_CACHE(CacheInvariant(), Panic(EMBCchInvPost)); |
|
3229 } |
|
3230 |
|
3231 |
|
3232 void DMmcMediaDriverFlash::BuildGammaArray(TInt64 aStart, TInt64 aEnd) |
|
3233 // |
|
3234 // iGamma is an array of indexes that correspond to cached blocks starting |
|
3235 // from aStart. iGamma[0] is the index of aStart, iGamma[1] is the index of |
|
3236 // aStart + iBlkLen, and so on. Building an array here means that all of |
|
3237 // the available cached entries can be found in linear time instead of |
|
3238 // quadratically searching through the array for each block. |
|
3239 // |
|
3240 { |
|
3241 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:bga:%lx,%lx", aStart, aEnd)); |
|
3242 |
|
3243 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EBGAStPos)); |
|
3244 __ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(EBGAStAlign)); |
|
3245 __ASSERT_DEBUG(aEnd > aStart, Panic(EBGANotPositive)); |
|
3246 __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EBGAEndPos)); |
|
3247 __ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(EBGAEndAlign)); |
|
3248 __ASSERT_DEBUG(aEnd - aStart <= (TInt64) iMaxBufSize, Panic(EBGAOverflow)); |
|
3249 __ASSERT_CACHE(CacheInvariant(), Panic(EBGACchInv)); |
|
3250 |
|
3251 // KNoCacheBlock = (0xff) x 4 |
|
3252 TUint blocksInRange = I64LOW((aEnd - aStart) >> iBlkLenLog2); |
|
3253 memset(iGamma, 0xff, sizeof(*iGamma) * blocksInRange); |
|
3254 |
|
3255 TInt64 blkAddr = 0; |
|
3256 for (TInt i = 0; ( (blocksInRange > 0 ) && (i < iBlocksInBuffer) ); ++i) |
|
3257 { |
|
3258 blkAddr = iCachedBlocks[i]; |
|
3259 if (blkAddr >= aStart && blkAddr < aEnd) |
|
3260 { |
|
3261 iGamma[I64LOW((blkAddr - aStart) >> iBlkLenLog2)] = i; |
|
3262 blocksInRange--; |
|
3263 } |
|
3264 } |
|
3265 } |
|
3266 |
|
3267 void DMmcMediaDriverFlash::InvalidateCache() |
|
3268 { |
|
3269 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ich")); |
|
3270 |
|
3271 // KInvalidBlock = (0xff) x 4 |
|
3272 memset(iCachedBlocks, 0xff, sizeof(*iCachedBlocks) * iBlocksInBuffer); |
|
3273 } |
|
3274 |
|
3275 // Invalidate any cache entries from aStart to aEnd |
|
3276 // This is for DMA writes and is to prevent the cache becoming inconsistent with the media. |
|
3277 void DMmcMediaDriverFlash::InvalidateCache(TInt64 aStart, TInt64 aEnd) |
|
3278 { |
|
3279 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ich:%lx,%lx", aStart, aEnd)); |
|
3280 |
|
3281 __ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EBGAStPos)); |
|
3282 __ASSERT_DEBUG(aEnd > aStart, Panic(EBGANotPositive)); |
|
3283 __ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EBGAEndPos)); |
|
3284 |
|
3285 const TInt blkCnt = I64LOW((aStart - aEnd) >> iBlkLenLog2); |
|
3286 |
|
3287 __ASSERT_CACHE(CacheInvariant(), Panic(EBGACchInv)); |
|
3288 |
|
3289 TInt64 endBlk = (blkCnt == 0) ? (aStart+iBlkLen) : aEnd; |
|
3290 |
|
3291 for (TInt i = 0; i < iBlocksInBuffer; ++i) |
|
3292 { |
|
3293 const TInt64 blkAddr = iCachedBlocks[i]; |
|
3294 if (blkAddr >= aStart && blkAddr < endBlk) |
|
3295 iCachedBlocks[i] = KInvalidBlock; |
|
3296 } |
|
3297 } |
|
3298 |
|
3299 TUint8* DMmcMediaDriverFlash::IdxToCchMem(TInt aIdx) const |
|
3300 { |
|
3301 __KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:icm:%d", aIdx)); |
|
3302 |
|
3303 __ASSERT_DEBUG(aIdx >= 0, Panic(EICMNegative)); |
|
3304 __ASSERT_DEBUG(aIdx < iBlocksInBuffer, Panic(EICMOverflow)); |
|
3305 |
|
3306 return &iCacheBuf[aIdx << iBlkLenLog2]; |
|
3307 } |
|
3308 |
|
3309 TInt DMmcMediaDriverFlash::CchMemToIdx(TUint8* aMemP) const |
|
3310 { |
|
3311 __ASSERT_DEBUG((aMemP >= iCacheBuf) && (aMemP < iCacheBuf + (iBlocksInBuffer << iBlkLenLog2)), Panic(ECMIOverflow)); |
|
3312 |
|
3313 return((aMemP - iCacheBuf) >> iBlkLenLog2); |
|
3314 } |
|
3315 |
|
3316 #ifdef _DEBUG_CACHE |
|
3317 TBool DMmcMediaDriverFlash::CacheInvariant() |
|
3318 // |
|
3319 // check each cache entry refers to a valid block and that no two |
|
3320 // entries cover the same block. This algorithm is quadratic in |
|
3321 // the cache length. |
|
3322 // |
|
3323 { |
|
3324 for (TInt i = 0; i < iBlocksInBuffer; ++i) |
|
3325 { |
|
3326 if (iCachedBlocks[i] == KInvalidBlock) |
|
3327 continue; |
|
3328 |
|
3329 if ((iCachedBlocks[i] & iBlkMsk) != 0) |
|
3330 return EFalse; |
|
3331 |
|
3332 if (iCachedBlocks[i] >= TotalSizeInBytes()) |
|
3333 return EFalse; |
|
3334 |
|
3335 for (TInt j = i + 1; j < iBlocksInBuffer; ++j) |
|
3336 { |
|
3337 if (iCachedBlocks[i] == iCachedBlocks[j]) |
|
3338 return EFalse; |
|
3339 } |
|
3340 } |
|
3341 |
|
3342 return ETrue; |
|
3343 } |
|
3344 #endif |
|
3345 |
|
3346 void DMmcMediaDriverFlash::NotifyPowerDown() |
|
3347 { |
|
3348 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Mmc:NotifyPowerDown")); |
|
3349 |
|
3350 iSessionEndDfc.Cancel(); |
|
3351 iDataTransferCallBackDfc.Cancel(); |
|
3352 |
|
3353 EndInCritical(); |
|
3354 |
|
3355 // need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once. |
|
3356 if (iSession) |
|
3357 iStack->CancelSession(iSession); |
|
3358 |
|
3359 CompleteRequest(KErrNotReady); |
|
3360 iMedReq = EMReqIdle; |
|
3361 } |
|
3362 |
|
3363 void DMmcMediaDriverFlash::NotifyEmergencyPowerDown() |
|
3364 { |
|
3365 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NotifyEmergencyPowerDown")); |
|
3366 |
|
3367 iSessionEndDfc.Cancel(); |
|
3368 iDataTransferCallBackDfc.Cancel(); |
|
3369 |
|
3370 TInt r=KErrNotReady; |
|
3371 if (iCritical) |
|
3372 r=KErrAbort; |
|
3373 EndInCritical(); |
|
3374 |
|
3375 // need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once. |
|
3376 if (iSession) |
|
3377 iStack->CancelSession(iSession); |
|
3378 |
|
3379 CompleteRequest(r); |
|
3380 iMedReq = EMReqIdle; |
|
3381 } |
|
3382 |
|
3383 TInt DMmcMediaDriverFlash::Request(TLocDrvRequest& aRequest) |
|
3384 { |
|
3385 __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x id %d",&aRequest,aRequest.Id())); |
|
3386 TInt r=KErrNotSupported; |
|
3387 TInt id=aRequest.Id(); |
|
3388 |
|
3389 #if defined (__TEST_PAGING_MEDIA_DRIVER__) |
|
3390 DThread* client=aRequest.Client(); |
|
3391 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("Client:0x%08x",client)); |
|
3392 #endif // __TEST_PAGING_MEDIA_DRIVER__ |
|
3393 |
|
3394 // First handle requests that can be handled without deferring |
|
3395 if(id==DLocalDrive::ECaps) |
|
3396 { |
|
3397 TLocalDriveCapsV6& c = *(TLocalDriveCapsV6*)aRequest.RemoteDes(); |
|
3398 TLocDrv& drive = *aRequest.Drive(); |
|
3399 r = Caps(drive, c); |
|
3400 c.iSize = drive.iPartitionLen; |
|
3401 c.iPartitionType = drive.iPartitionType; |
|
3402 c.iHiddenSectors = (TUint) (drive.iPartitionBaseAddr >> KDiskSectorShift); |
|
3403 return r; |
|
3404 } |
|
3405 |
|
3406 // All other requests must be deferred if a request is currently in progress |
|
3407 if (iCurrentReq) |
|
3408 { |
|
3409 |
|
3410 #if defined(__TEST_PAGING_MEDIA_DRIVER__) |
|
3411 if (DMediaPagingDevice::PageInRequest(*iCurrentReq)) |
|
3412 iMmcStats.iReqPage++; |
|
3413 else |
|
3414 iMmcStats.iReqNormal++; |
|
3415 #endif // __TEST_PAGING_MEDIA_DRIVER__ |
|
3416 |
|
3417 // a request is already in progress, so hold on to this one |
|
3418 __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x ret 1",&aRequest)); |
|
3419 return KMediaDriverDeferRequest; |
|
3420 } |
|
3421 else |
|
3422 { |
|
3423 iCurrentReq=&aRequest; |
|
3424 TUint partitionType = iCurrentReq->Drive()->iPartitionType; |
|
3425 TBool readOnly = (partitionType == KPartitionTypeRofs || partitionType == KPartitionTypeROM); |
|
3426 |
|
3427 switch (id) |
|
3428 { |
|
3429 |
|
3430 |
|
3431 #if defined(__DEMAND_PAGING__) |
|
3432 case DMediaPagingDevice::ERomPageInRequest: |
|
3433 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Request(ERomPageInRequest)")); |
|
3434 BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_MMC,iCurrentReq); |
|
3435 r=DoRead(); |
|
3436 break; |
|
3437 case DMediaPagingDevice::ECodePageInRequest: |
|
3438 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Request(ECodePageInRequest)")); |
|
3439 BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_MMC,iCurrentReq); |
|
3440 r=DoRead(); |
|
3441 break; |
|
3442 #endif // __DEMAND_PAGING__ |
|
3443 |
|
3444 case DLocalDrive::EQueryDevice: |
|
3445 r = KErrNotSupported; |
|
3446 break; |
|
3447 |
|
3448 case DLocalDrive::ERead: |
|
3449 r=DoRead(); |
|
3450 break; |
|
3451 case DLocalDrive::EWrite: |
|
3452 if (readOnly) |
|
3453 return KErrNotSupported; |
|
3454 r=DoWrite(); |
|
3455 break; |
|
3456 case DLocalDrive::EFormat: |
|
3457 if (readOnly) |
|
3458 return KErrNotSupported; |
|
3459 r=DoFormat(); |
|
3460 break; |
|
3461 |
|
3462 #if defined __TEST_PAGING_MEDIA_DRIVER__ |
|
3463 case DLocalDrive::EControlIO: |
|
3464 { |
|
3465 r = HandleControlIORequest(); |
|
3466 break; |
|
3467 } |
|
3468 #endif |
|
3469 |
|
3470 case DLocalDrive::EPasswordUnlock: |
|
3471 case DLocalDrive::EPasswordLock: |
|
3472 case DLocalDrive::EPasswordClear: |
|
3473 // Don't allow passords on internal MMC; one reason is that this may be used for paging and |
|
3474 // we can't really stop paging just because the password hasn't been supplied |
|
3475 if (iInternalSlot) |
|
3476 r = KErrNotSupported; |
|
3477 else |
|
3478 r = DoPasswordOp(); |
|
3479 break; |
|
3480 case DLocalDrive::EPasswordErase: |
|
3481 { |
|
3482 r = LaunchRPIErase(); |
|
3483 // This will complete the request in the event of an error |
|
3484 if(r != KErrNone) |
|
3485 PartitionInfoComplete(r); |
|
3486 |
|
3487 r = KErrNone; // ensures to indicate asynchronoous completion |
|
3488 break; |
|
3489 } |
|
3490 case DLocalDrive::EWritePasswordStore: |
|
3491 { |
|
3492 // |
|
3493 // If the card is ready and locked, request the stack to perform the |
|
3494 // auto-unlock sequence. This is required, as the stack only performs |
|
3495 // automatic unlocking during power-up, and the stack may already be powered. |
|
3496 // |
|
3497 r = KErrNone; // asynchronous completion |
|
3498 |
|
3499 if(iCard->IsReady() && iCard->IsLocked()) |
|
3500 { |
|
3501 iSession->SetupCIMAutoUnlock(); |
|
3502 if(EngageAndSetRequest(EMReqWritePasswordData, 0) != KErrNone) |
|
3503 { |
|
3504 // If error, complete with KErrNone anyway |
|
3505 // - The password store has been set, any errors |
|
3506 // will be reported on the next access. |
|
3507 CompleteRequest(KErrNone); |
|
3508 } |
|
3509 } |
|
3510 else |
|
3511 { |
|
3512 CompleteRequest(KErrNone); |
|
3513 } |
|
3514 break; |
|
3515 } |
|
3516 case DLocalDrive::EEnlarge: |
|
3517 case DLocalDrive::EReduce: |
|
3518 default: |
|
3519 r=KErrNotSupported; |
|
3520 break; |
|
3521 } |
|
3522 } |
|
3523 |
|
3524 __KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x cmp %d",&aRequest,r)); |
|
3525 |
|
3526 if (r != KErrNone) |
|
3527 { |
|
3528 iMedReq = EMReqIdle; |
|
3529 iCurrentReq=NULL; |
|
3530 SetCurrentConsumption(KIdleCurrentInMilliAmps); |
|
3531 } |
|
3532 |
|
3533 return r; |
|
3534 } |
|
3535 |
|
3536 void DMmcMediaDriverFlash::Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg) |
|
3537 { |
|
3538 // Complete using the default implementation |
|
3539 DMediaDriver::Disconnect(aLocalDrive, aMsg); |
|
3540 } |
|
3541 |
|
3542 #ifdef _DEBUG_CACHE |
|
3543 TUint8* DMmcMediaDriverFlash::GetCachedBlock(TInt64 aMdAddr) |
|
3544 // |
|
3545 // return cache block for media at aMdAddr, 0 if not found. |
|
3546 // This is a debug function to determine whether or not a block is in |
|
3547 // the cache. It should not be used for general block retrieval. |
|
3548 // If there are m blocks in the cache, and n in the requested range, |
|
3549 // this function is o(mn), whereas BuildGammaArray() is theta(m). |
|
3550 // |
|
3551 { |
|
3552 __KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:gcb:%lx", aMdAddr)); |
|
3553 |
|
3554 __ASSERT_DEBUG((aMdAddr & iBlkMsk) == 0, Panic(EGCBAlign)); |
|
3555 __ASSERT_DEBUG(TotalSizeInBytes() > aMdAddr, Panic(EGCBPos)); |
|
3556 __ASSERT_CACHE(CacheInvariant(), Panic(EGCBCchInv)); |
|
3557 |
|
3558 for (TInt i = 0; i < iBlocksInBuffer; ++i) |
|
3559 { |
|
3560 if (iCachedBlocks[i] == aMdAddr) |
|
3561 { |
|
3562 TUint8* raby = IdxToCchMem(i); |
|
3563 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:gcb:%x", (TUint32) raby)); |
|
3564 return raby; |
|
3565 } |
|
3566 } |
|
3567 |
|
3568 __KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:gcb:0")); |
|
3569 return 0; |
|
3570 } |
|
3571 #endif // _DEBUG_CACHE |
|
3572 |
|
3573 |
|
3574 #if defined(__TEST_PAGING_MEDIA_DRIVER__) |
|
3575 /** |
|
3576 Handles a ControlIO request to the MMC media driver. |
|
3577 made by one of the MMC paging tests |
|
3578 |
|
3579 @internalTechnology |
|
3580 |
|
3581 @return Corresponding Symbian OS error code |
|
3582 */ |
|
3583 TInt DMmcMediaDriverFlash::HandleControlIORequest() |
|
3584 { |
|
3585 const TInt command = iCurrentReq->Int0(); |
|
3586 TAny* aParam1 = iCurrentReq->Ptr1(); |
|
3587 // TAny* aParam2 = iCurrentReq->Ptr2(); |
|
3588 |
|
3589 TInt r = KErrCompletion; |
|
3590 |
|
3591 __KTRACE_OPT(KLOCDPAGING,Kern::Printf("[MD : ] HandleControlIORequest aCommand: 0x%x", command)); |
|
3592 |
|
3593 |
|
3594 switch (command) |
|
3595 { |
|
3596 case KMmcGetStats: |
|
3597 { |
|
3598 DThread* pC = iCurrentReq->Client(); |
|
3599 DThread* pT = iCurrentReq->RemoteThread(); |
|
3600 if (!pT) |
|
3601 pT = pC; |
|
3602 Kern::ThreadRawWrite(pT, aParam1, &iMmcStats, sizeof(iMmcStats), pC); |
|
3603 |
|
3604 iMmcStats.iReqNormal=0; |
|
3605 iMmcStats.iNormalFragmenting=0; |
|
3606 iMmcStats.iClashFragmenting=0; |
|
3607 |
|
3608 break; |
|
3609 } |
|
3610 default: |
|
3611 r=KErrNotSupported; |
|
3612 break; |
|
3613 } |
|
3614 |
|
3615 return r; |
|
3616 } |
|
3617 #endif // __TEST_PAGING_MEDIA_DRIVER__ |
|
3618 |
|
3619 |
|
3620 |
|
3621 |
|
3622 DECLARE_EXTENSION_PDD() |
|
3623 { |
|
3624 // NB if the media driver has been defined as a kernel extension in the .OBY/.IBY file |
|
3625 // i.e the "extension" keyword has been used rather than "device", then an instance of |
|
3626 // DPhysicalDeviceMediaMmcFlash will already have been created by InitExtension(). In this |
|
3627 // case the kernel will see that an object of the same name already exists and delete the |
|
3628 // new one. |
|
3629 return new DPhysicalDeviceMediaMmcFlash; |
|
3630 } |
|
3631 DECLARE_STANDARD_EXTENSION() |
|
3632 { |
|
3633 __KTRACE_OPT(KBOOT,Kern::Printf("Creating MMCDrv PDD")); |
|
3634 |
|
3635 DPhysicalDeviceMediaMmcFlash* device = new DPhysicalDeviceMediaMmcFlash; |
|
3636 |
|
3637 TInt r; |
|
3638 if (device==NULL) |
|
3639 r=KErrNoMemory; |
|
3640 else |
|
3641 r=Kern::InstallPhysicalDevice(device); |
|
3642 __KTRACE_OPT(KBOOT,Kern::Printf("Installing MMCDrv PDD in kernel returned %d",r)); |
|
3643 |
|
3644 __KTRACE_OPT(KBOOT,Kern::Printf("Mmc extension entry point drive returns %d",r)); |
|
3645 return r; |
|
3646 } |
|
3647 |
|
3648 |