|
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // D_MEDNAND.CPP |
|
15 // |
|
16 // |
|
17 |
|
18 #define _MEDIA_DRIVER |
|
19 #include <nand_media.h> |
|
20 #include <emulator.h> |
|
21 #include <property.h> |
|
22 |
|
23 /******************************************** |
|
24 * Driver definitions |
|
25 ********************************************/ |
|
26 const TInt KSimulatedDeviceId = 0xEC73; |
|
27 const CHAR KNandFileName[] = "NANDDRV.BIN"; |
|
28 |
|
29 // |
|
30 // Platform dependent media driver class |
|
31 // |
|
32 class DMediaDriverNandWin32 : public DMediaDriverNand |
|
33 { |
|
34 public: |
|
35 DMediaDriverNandWin32(TMediaDevice aDevice); |
|
36 |
|
37 // replacing pure virtual - NAND device specific stuff |
|
38 virtual TInt Initialise(); |
|
39 virtual TInt GetDeviceId(TUint8& aDeviceId, TUint8& aManufacturerId); |
|
40 virtual TInt DeviceRead(const TUint aPageAddress, TAny* aBuf, const TUint aLength); |
|
41 virtual TInt DeviceWrite(const TUint aPageAddress, TAny* aBuf, const TUint aLength); |
|
42 virtual TInt DeviceErase(const TUint aBlockAddress); |
|
43 virtual TInt DeviceClose(); |
|
44 |
|
45 public: |
|
46 HANDLE iFile; |
|
47 HANDLE iMapping; |
|
48 TUint8* iBase; |
|
49 }; |
|
50 |
|
51 LOCAL_C TInt MapLastError() |
|
52 // |
|
53 // Map an NT error to an Epoc/32 error. |
|
54 // |
|
55 { |
|
56 __PATH_NOT_YET_TESTED; |
|
57 DWORD r=GetLastError(); |
|
58 TInt res; |
|
59 switch (r) |
|
60 { |
|
61 case ERROR_SHARING_VIOLATION : res=KErrAccessDenied; break; |
|
62 case ERROR_LOCK_VIOLATION : res=KErrLocked; break; |
|
63 case ERROR_FILE_NOT_FOUND: res=KErrNotFound; break; |
|
64 case ERROR_PATH_NOT_FOUND: res=KErrPathNotFound; break; |
|
65 case ERROR_ALREADY_EXISTS: |
|
66 case ERROR_FILE_EXISTS: |
|
67 res=KErrAlreadyExists; |
|
68 break; |
|
69 case ERROR_NOT_READY: res=KErrNotReady; break; |
|
70 case ERROR_UNRECOGNIZED_VOLUME: |
|
71 case ERROR_NOT_DOS_DISK: |
|
72 res=KErrUnknown; |
|
73 break; |
|
74 case ERROR_UNRECOGNIZED_MEDIA: res=KErrCorrupt; break; |
|
75 case ERROR_INVALID_NAME: res=KErrBadName; break; |
|
76 case ERROR_NO_MORE_FILES: res=KErrEof; break; |
|
77 case ERROR_DISK_FULL: res=KErrDiskFull; break; |
|
78 default: res=KErrGeneral; |
|
79 } |
|
80 return(res); |
|
81 } |
|
82 |
|
83 TInt DMediaDriverNandWin32::Initialise() |
|
84 // |
|
85 // Create the simulated NAND file if necessary and |
|
86 // map it into memory. |
|
87 // |
|
88 { |
|
89 __PATH_TESTED; |
|
90 |
|
91 // locate/open the file that models the flash |
|
92 CHAR filename[MAX_PATH]; |
|
93 strcpy(filename, Property::GetString("EmulatorMediaPath")); |
|
94 if (!Emulator::CreateAllDirectories(filename)) |
|
95 { |
|
96 __PATH_NOT_YET_TESTED; |
|
97 return Emulator::LastError(); |
|
98 } |
|
99 strcat(filename, KNandFileName); |
|
100 iFile = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); |
|
101 |
|
102 if (iFile == INVALID_HANDLE_VALUE) |
|
103 { |
|
104 __PATH_NOT_YET_TESTED; |
|
105 return Emulator::LastError(); |
|
106 } |
|
107 |
|
108 const TUint32 flashSizeInBytes = iNumBlocks * iNumPagesPerBlock * (iNumBytesMain + iNumBytesSpare); |
|
109 |
|
110 SetFilePointer(iFile, flashSizeInBytes, NULL, FILE_BEGIN); |
|
111 SetEndOfFile(iFile); |
|
112 |
|
113 iMapping = CreateFileMappingA(iFile, NULL, PAGE_READWRITE, 0, flashSizeInBytes, NULL); |
|
114 if (iMapping == NULL) |
|
115 { |
|
116 __PATH_NOT_YET_TESTED; |
|
117 return Emulator::LastError(); |
|
118 } |
|
119 |
|
120 iBase = (TUint8*)MapViewOfFile(iMapping, FILE_MAP_WRITE, 0, 0, flashSizeInBytes); |
|
121 if (iBase == NULL) |
|
122 { |
|
123 __PATH_NOT_YET_TESTED; |
|
124 return Emulator::LastError(); |
|
125 } |
|
126 |
|
127 return KErrNone; |
|
128 } |
|
129 |
|
130 TInt DMediaDriverNandWin32::GetDeviceId(TUint8& aDeviceId, TUint8& aManufacturerId) |
|
131 { |
|
132 __PATH_TESTED; |
|
133 |
|
134 aManufacturerId = (KSimulatedDeviceId & 0xFF00) >> 8; |
|
135 aDeviceId = (KSimulatedDeviceId & 0xFF); |
|
136 return KErrNone; |
|
137 } |
|
138 |
|
139 TInt DMediaDriverNandWin32::DeviceRead(const TUint aPageAddress, TAny* aBuf, const TUint aLength) |
|
140 { |
|
141 __PATH_TESTED; |
|
142 |
|
143 __NAND_ASSERT(aPageAddress < (iNumBlocks * iNumPagesPerBlock)); |
|
144 __NAND_ASSERT( (aLength == iNumBytesMain) |
|
145 || (aLength == iNumBytesMain + iNumBytesSpare) |
|
146 || (aLength == iNumBytesSpare) ); |
|
147 |
|
148 #ifdef __TEST_MEDIA_DRIVER__ |
|
149 extern TBool gNoPower; |
|
150 if(gNoPower) |
|
151 return KErrBadPower; |
|
152 #endif |
|
153 |
|
154 TUint8* readPoint; |
|
155 if (aLength == iNumBytesMain) |
|
156 { |
|
157 __PATH_TESTED; |
|
158 readPoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare)); |
|
159 } |
|
160 else if (aLength == iNumBytesSpare) |
|
161 { |
|
162 __PATH_TESTED; |
|
163 readPoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare)) + iNumBytesMain; |
|
164 } |
|
165 else if (aLength == (iNumBytesMain + iNumBytesSpare)) |
|
166 { |
|
167 __PATH_TESTED; |
|
168 readPoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare)); |
|
169 } |
|
170 else |
|
171 { |
|
172 __PATH_NOT_YET_TESTED; |
|
173 return KErrArgument; |
|
174 } |
|
175 |
|
176 for (TUint i = 0; i < aLength; i++) |
|
177 { |
|
178 ((TUint8*)aBuf)[i] = readPoint[i]; |
|
179 } |
|
180 |
|
181 #ifdef __TEST_MEDIA_DRIVER__ |
|
182 extern TBool gECCFail; |
|
183 if(gECCFail) |
|
184 { |
|
185 //introduce a random one bit error |
|
186 TUint8* p=(TUint8*)aBuf; |
|
187 TUint32 key=Kern::Random() % aLength; |
|
188 TUint32 shift=1<<(Kern::Random() % 8); |
|
189 p[key]=(TUint8)(p[key]&shift?p[key]-shift:p[key]+shift); |
|
190 gECCFail=EFalse; |
|
191 } |
|
192 #endif |
|
193 |
|
194 return KErrNone; |
|
195 } |
|
196 |
|
197 #ifdef __TEST_MEDIA_DRIVER__ |
|
198 extern "C" TUint32 gbbm_get_sphy_blknum(TUint32, TUint32); |
|
199 #endif |
|
200 TInt DMediaDriverNandWin32::DeviceWrite(const TUint aPageAddress, TAny* aBuf, const TUint aLength) |
|
201 { |
|
202 __PATH_TESTED; |
|
203 |
|
204 __NAND_ASSERT(aPageAddress < (iNumBlocks * iNumPagesPerBlock)); |
|
205 __NAND_ASSERT( (aLength == iNumBytesMain) |
|
206 || (aLength == iNumBytesMain + iNumBytesSpare) |
|
207 || (aLength == iNumBytesSpare) ); |
|
208 |
|
209 #ifdef __TEST_MEDIA_DRIVER__ |
|
210 extern TBool gNoPower; |
|
211 extern TBool gPowerFail; |
|
212 extern TUint32 gPowerFailAfter; |
|
213 if(gNoPower) |
|
214 return KErrBadPower; |
|
215 if(gPowerFail) |
|
216 { |
|
217 if(gPowerFailAfter) |
|
218 --gPowerFailAfter; |
|
219 else |
|
220 { |
|
221 gPowerFail=EFalse; |
|
222 gNoPower=ETrue; |
|
223 extern TUint32 gNotificationType; |
|
224 extern TUint32 KNandDbgNotifyPowerDown; |
|
225 extern TInt NotifyThread(); |
|
226 if(gNotificationType==KNandDbgNotifyPowerDown) |
|
227 NotifyThread(); |
|
228 return KErrBadPower; |
|
229 } |
|
230 } |
|
231 #endif |
|
232 |
|
233 TUint8* writePoint; |
|
234 |
|
235 if (aLength == iNumBytesMain) |
|
236 { |
|
237 __PATH_TESTED; |
|
238 writePoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare)); |
|
239 } |
|
240 else if (aLength == iNumBytesSpare) |
|
241 { |
|
242 __PATH_TESTED; |
|
243 writePoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare)) + iNumBytesMain; |
|
244 } |
|
245 else if (aLength == (iNumBytesMain + iNumBytesSpare)) |
|
246 { |
|
247 __PATH_TESTED; |
|
248 writePoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare)); |
|
249 } |
|
250 else |
|
251 { |
|
252 __PATH_NOT_YET_TESTED; |
|
253 return KErrArgument; |
|
254 } |
|
255 |
|
256 for (TUint i = 0; i < aLength; i++) |
|
257 { |
|
258 writePoint[i] &= ((TUint8*)aBuf)[i]; |
|
259 } |
|
260 |
|
261 #ifdef __TEST_MEDIA_DRIVER__ |
|
262 extern TUint32 gFailAfter; |
|
263 extern TUint32 gFailAfterCnt; |
|
264 extern TBool gFailureType; //true-WriteFail, false-EraseFail |
|
265 extern TBool gFailON; |
|
266 if(gFailON && gFailureType) |
|
267 { |
|
268 if(gFailAfterCnt) |
|
269 --gFailAfterCnt; |
|
270 else |
|
271 { |
|
272 extern TUint32 FirstReadPUN; |
|
273 extern DMediaDriverNand* gMediaDriverPtr; |
|
274 if(gbbm_get_sphy_blknum(0,aPageAddress/gMediaDriverPtr->iNumPagesPerBlock)==FirstReadPUN) |
|
275 { |
|
276 gFailAfterCnt=gFailAfter; |
|
277 //notify failure |
|
278 extern TUint32 gNotificationType; |
|
279 extern TUint32 KNandDbgNotifyWriteFail; |
|
280 extern TInt NotifyThread(); |
|
281 if(gNotificationType==KNandDbgNotifyWriteFail) |
|
282 NotifyThread(); |
|
283 |
|
284 return KErrCorrupt; |
|
285 } |
|
286 } |
|
287 } |
|
288 #endif |
|
289 |
|
290 return KErrNone; |
|
291 } |
|
292 |
|
293 TInt DMediaDriverNandWin32::DeviceErase(const TUint aBlockAddress) |
|
294 { |
|
295 __PATH_TESTED; |
|
296 |
|
297 __NAND_ASSERT(aBlockAddress < iNumBlocks); |
|
298 #ifdef __TEST_MEDIA_DRIVER__ |
|
299 extern TBool gNoPower; |
|
300 extern TBool gPowerFail; |
|
301 extern TUint32 gPowerFailAfter; |
|
302 if(gNoPower) |
|
303 return KErrBadPower; |
|
304 if(gPowerFail) |
|
305 { |
|
306 if(gPowerFailAfter) |
|
307 --gPowerFailAfter; |
|
308 else |
|
309 { |
|
310 gPowerFail=EFalse; |
|
311 gNoPower=ETrue; |
|
312 extern TUint32 gNotificationType; |
|
313 extern TUint32 KNandDbgNotifyPowerDown; |
|
314 extern TInt NotifyThread(); |
|
315 if(gNotificationType==KNandDbgNotifyPowerDown) |
|
316 NotifyThread(); |
|
317 return KErrBadPower; |
|
318 } |
|
319 } |
|
320 #endif |
|
321 |
|
322 const TUint bytesPerEraseBlock = iNumPagesPerBlock * (iNumBytesMain + iNumBytesSpare); |
|
323 const TUint erasePos = aBlockAddress * bytesPerEraseBlock; |
|
324 |
|
325 TUint8* temp = iBase + erasePos; |
|
326 for (TUint i=0; i < bytesPerEraseBlock; i++) |
|
327 { |
|
328 temp[i]=0xFF; |
|
329 } |
|
330 return KErrNone; |
|
331 } |
|
332 |
|
333 TInt DMediaDriverNandWin32::DeviceClose() |
|
334 { |
|
335 __PATH_NOT_YET_TESTED; |
|
336 TBool bRtn=UnmapViewOfFile(iBase); |
|
337 if(!bRtn) |
|
338 { |
|
339 __PATH_NOT_YET_TESTED; |
|
340 return(MapLastError()); |
|
341 } |
|
342 |
|
343 bRtn=CloseHandle(iMapping); |
|
344 if (!bRtn) |
|
345 { |
|
346 __PATH_NOT_YET_TESTED; |
|
347 return(MapLastError()); |
|
348 } |
|
349 |
|
350 bRtn=CloseHandle(iFile); |
|
351 if (!bRtn) |
|
352 { |
|
353 __PATH_NOT_YET_TESTED; |
|
354 return(MapLastError()); |
|
355 } |
|
356 |
|
357 return KErrNone; |
|
358 } |
|
359 |
|
360 DMediaDriverNandWin32::DMediaDriverNandWin32(TMediaDevice aDevice) |
|
361 : DMediaDriverNand(aDevice) |
|
362 { |
|
363 __PATH_TESTED; |
|
364 } |
|
365 |
|
366 DMediaDriverNand* DMediaDriverNand::New(TMediaDevice aDevice) |
|
367 { |
|
368 __PATH_TESTED; |
|
369 return new DMediaDriverNandWin32(aDevice); |
|
370 } |
|
371 |
|
372 #ifdef __USE_CUSTOM_ALLOCATOR |
|
373 /** |
|
374 Concrete implementation of the NAND buffer allocator class |
|
375 - Uses Kern::Alloc based allocation |
|
376 |
|
377 @internalTechnology |
|
378 */ |
|
379 class TNandAllocatorWins : public TNandAllocatorBase |
|
380 { |
|
381 public: |
|
382 virtual TInt AllocateBuffers(SBufferInfo& aBufferInfo); // Initialise the allocator |
|
383 }; |
|
384 |
|
385 /** Concrete implementation of the NAND buffer allocator class |
|
386 Creates a customallocator (using Kern::Alloc) |
|
387 |
|
388 @param aBufferInfo A reference to a SBufferInfo containing the details of the PSL allocated buffer |
|
389 @return Standard Symbian OS error code |
|
390 @see TNandAllocatorBase::SCellInfo |
|
391 */ |
|
392 TInt TNandAllocatorWins::AllocateBuffers(SBufferInfo& aBufferInfo) |
|
393 { |
|
394 const TUint32 KNumBuffers = 4; |
|
395 const TUint32 KMaxNumBytesSpare = 16; |
|
396 const TUint32 KMaxNumBytesMain = 512; |
|
397 const TUint32 KMaxNumBytesPage = KMaxNumBytesSpare + KMaxNumBytesMain; |
|
398 |
|
399 aBufferInfo.iBytesPerSpareArray = KMaxNumBytesSpare; |
|
400 aBufferInfo.iBytesPerMainArray = KMaxNumBytesMain; |
|
401 aBufferInfo.iBufferCount = KNumBuffers; |
|
402 |
|
403 aBufferInfo.iBufferP = reinterpret_cast<TUint8*>(Kern::Alloc(KMaxNumBytesPage * KNumBuffers)); |
|
404 |
|
405 return(aBufferInfo.iBufferP ? KErrNone : KErrNoMemory); |
|
406 } |
|
407 |
|
408 /** |
|
409 Create an allocator suitable for use on this target |
|
410 @internalComponent |
|
411 */ |
|
412 TNandAllocatorBase* DMediaDriverNand::ExtensionInitAllocator() |
|
413 { |
|
414 return new TNandAllocatorWins; |
|
415 } |
|
416 #endif |