First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // wins\specific\lffsdev.cpp
18 #include <flash_media.h>
22 #define FLASH_FAULT() Kern::Fault("LFFSDEV",__LINE__)
24 //#define M18_EMULATION // Test for Control Mode operation
26 /********************************************
28 ********************************************/
30 /** LFFS image name */
31 const CHAR KLfsFileName[] = "LFSLDRV.BIN";
34 //-- default values for LFFS related entries in "epoc.ini" file
35 const TInt KDefaultFlashSize = 0x400000; //-- "FlashSize" entry, default 4MB
36 const TInt KEraseBlockSize = 0x20000; //-- "FlashEraseSize" entry, default 128KB
37 const TUint32 KFlashEraseTime = 1000000; //-- "FlashEraseTime" entry, default 1s
38 const TInt KWriteBlockSize = 64; //-- "FlashWriteSize" entry
39 const TInt KFlashWriteTime = 406; //-- "FlashWriteTime" entry, default 406us
40 const TInt KResumeTime = 5000; //-- "FlashResumeTime" entry, default 5ms
42 //-- other possible LFFS related entries in "epoc.ini" file:
43 //-- "FlashHoldOffTime" default value = iEraseTime/10
45 //-- "FlashForceImgMount" default value = 0. If not 0 LFFS image will be mounted as it is, even if it doesn't have TLfsParams structure in the end.
46 //-- Moreover, it won't be zero filled and TLfsParams structure won't be written at the end of the image file.
47 //-- shall be useful for dealing with real images from the real devices
51 This cunning structure is supposed to be at the very end of the LFFS image file. If it is not foung there,
52 the image gets zero-filled (depends on "FlashForceImgMount" flag in epoc.ini).
61 /***************************************************
62 * ControlIO command types - for debug builds, only
63 ***************************************************/
73 const TInt KDataBufSize=1024;
75 /********************************************
77 ********************************************/
78 class DMediaDriverFlashWin32 : public DMediaDriverFlash
93 DMediaDriverFlashWin32(TInt aMediaId);
95 // replacing pure virtual - FLASH device specific stuff
96 virtual TInt Initialise();
97 virtual TUint32 EraseBlockSize();
98 virtual TUint32 TotalSize();
99 virtual TInt DoRead();
100 virtual TInt DoWrite();
101 virtual TInt DoErase();
102 virtual TInt Caps(TLocalDriveCapsV2& caps);
105 void StartTimer(TInt aMicros);
108 void CompleteErase();
109 void CompleteWrite();
110 void CompleteSuspend();
111 void StartPendingRW();
112 void ReadFlashParameters();
114 static void TimerFn(TAny* aPtr);
115 static void EventDfc(TAny* aPtr);
118 enum TCtrlIoState {/*EIdle=0,ECtrlIoWaitWr=1,ECtrlIoWaitRd=2,ECtrlIoWrActive=3,*/ECtrlIoTimeOutPrep=4};
119 TInt ControlIO(TInt aCommand,TAny* aParam1,TAny* /*aParam2*/);
120 TInt Request(TLocDrvRequest& m);
126 TInt iEraseBlockSize;
128 TInt iSuspendHoldOffTime;
130 TInt iWriteBlockSize;
136 TUint8* iData; // data being written
141 TUint32 iEraseCounter;
151 DMediaDriverFlashWin32::DMediaDriverFlashWin32(TInt aMediaId)
152 : DMediaDriverFlash(aMediaId),
153 iTimer(&TimerFn,this),
154 iEventDfc(&EventDfc,this,NULL,2),
155 iTickPeriod(NKern::TickPeriod())
159 //iCtrlIoState=EIdle;
164 void DMediaDriverFlashWin32::ReadFlashParameters()
166 // Read the flash parameters from the ini file, or use defaults
170 iSize = Property::GetInt("FlashSize", KDefaultFlashSize);
172 TInt nblocks = Property::GetInt("FlashEraseBlocks", 0);
174 nblocks = iSize/Property::GetInt("FlashEraseSize", KEraseBlockSize);
176 iEraseBlockSize = iSize / nblocks;
177 __ASSERT_ALWAYS(iEraseBlockSize * nblocks == iSize, FLASH_FAULT());
178 __ASSERT_ALWAYS((iEraseBlockSize & (iEraseBlockSize-1)) == 0, FLASH_FAULT());
180 iEraseTime = Property::GetInt("FlashEraseTime", KFlashEraseTime);
182 iSuspendHoldOffTime = Property::GetInt("FlashHoldOffTime", iEraseTime/10);
183 iResumeTime = Property::GetInt("FlashResumeTime", KResumeTime);
184 iWriteBlockSize = Property::GetInt("FlashWriteSize", KWriteBlockSize);
185 __ASSERT_ALWAYS((iWriteBlockSize & (iWriteBlockSize-1)) == 0, FLASH_FAULT());
187 iWriteTime = Property::GetInt("FlashWriteTime", KFlashWriteTime);
191 TInt DMediaDriverFlashWin32::Initialise()
193 iEventDfc.SetDfcQ(iPrimaryMedia->iDfcQ);
194 iData=(TUint8*)Kern::Alloc(KDataBufSize);
198 ReadFlashParameters();
200 // locate/open the file that models the flash
201 CHAR filename[MAX_PATH];
202 strcpy(filename, Property::GetString("EmulatorMediaPath"));
203 if (!Emulator::CreateAllDirectories(filename))
204 return Emulator::LastError();
205 strcat(filename, KLfsFileName);
207 iFile = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL);
208 if (iFile == INVALID_HANDLE_VALUE)
209 return Emulator::LastError();
216 //-- try to read TLfsParams structure from the end of the image file.
217 if (SetFilePointer(iFile, iSize, NULL, FILE_BEGIN) != -1
218 && ReadFile(iFile, &p, sizeof(TLfsParams), &bytes, NULL)
219 && p.iEraseSize == iEraseBlockSize)
221 valid = ETrue; //-- read it OK.
224 {//-- couldn't read TLfsParams structure from the end of the image file.
225 //-- if "FlashForceImgMount" parameter from epoc.ini is 0 or not present,
226 //-- zero-fill the lffs image file and write TLfsParams structure at the end of the file.
228 const TInt forceImgMount = Property::GetInt("FlashForceImgMount", 0);
231 p.iEraseSize = iEraseBlockSize;
232 if (SetFilePointer(iFile,iSize, NULL, FILE_BEGIN) == -1
233 || !WriteFile(iFile, &p, sizeof(p), &bytes, NULL)
234 || !SetEndOfFile(iFile))
235 return Emulator::LastError();
240 {//-- mount LFFS image forcingly.
245 iMapping = CreateFileMappingA(iFile, NULL, PAGE_READWRITE, 0, iSize, NULL);
246 if (iMapping == NULL)
247 return Emulator::LastError();
249 iBase = (TUint8*)MapViewOfFile(iMapping, FILE_MAP_WRITE, 0, 0, iSize);
251 return Emulator::LastError();
253 //-- zero-fill media image it doesn't contain TLfsParams data at the very end.
256 memclr(iBase, iSize);
262 TUint32 DMediaDriverFlashWin32::EraseBlockSize()
264 return iEraseBlockSize;
267 TUint32 DMediaDriverFlashWin32::TotalSize()
272 TInt DMediaDriverFlashWin32::DoRead()
275 return 1; // write in progress so defer read
277 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoRead"));
279 if (iState==EErasePending)
284 if (iState==EIdle || iState==ESuspended)
286 // can do the read now
287 TInt pos=(TInt)iReadReq->Pos();
288 TInt len=(TInt)iReadReq->Length();
290 TPtrC8 des(iBase+pos,len);
291 TInt r=iReadReq->WriteRemote(&des,0);
292 Complete(EReqRead,r);
293 if (iState==ESuspended)
296 else if (iState==EErase)
298 // erase in progress - suspend it
301 else if (iState==EEraseNoSuspend)
302 iState=ESuspendPending;
303 // wait for suspend to complete
307 TInt DMediaDriverFlashWin32::DoWrite()
310 return 1; // read in progress so defer write
312 if (iState==EErasePending)
317 if (iState==EIdle || iState==ESuspended)
319 // can start the write now
320 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Write Pos=%08x Length=%08x RemDesOff=%08x",
321 (TInt)iWriteReq->Pos(),(TInt)iWriteReq->Length(),iWriteReq->RemoteDesOffset()));
324 TInt pos = (TInt)iWriteReq->Pos();
325 TInt end = pos + (TInt)iWriteReq->Length();
326 pos &= ~(iWriteBlockSize-1);
327 end = (end + iWriteBlockSize-1) & ~(iWriteBlockSize-1);
328 StartTimer(((end-pos)/iWriteBlockSize) * iWriteTime);
330 else if (iState==EErase)
332 // erase in progress - suspend it
335 else if (iState==EEraseNoSuspend)
336 iState=ESuspendPending;
337 // wait for suspend to complete
341 void DMediaDriverFlashWin32::CompleteWrite()
343 // Do the actual write in the completion
344 // Transfer data in blocks from the client and AND it to the 'flash'
347 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:WriteComplete"));
350 TUint8* flash = iBase + (TInt)iWriteReq->Pos();
351 TInt len = (TInt)iWriteReq->Length();
355 TInt size = Min(len, KDataBufSize);
356 TPtr8 des(iData,size);
357 r = iWriteReq->ReadRemote(&des, offset);
362 const TUint8* ptr = iData;
366 } while (--size > 0);
369 if (iState == EWriting)
371 Complete(EReqWrite,r);
372 if (iState == ESuspended)
376 TInt DMediaDriverFlashWin32::DoErase()
378 if (iReadReq || iWriteReq)
379 return 1; // read or write in progress so defer this request
380 TInt pos=(TUint32)iEraseReq->Pos();
381 TInt len=(TUint32)iEraseReq->Length();
382 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoErase %d@%08x",len,pos));
383 if (len!=iEraseBlockSize)
384 return KErrArgument; // only allow single-block erase
385 if (pos & (iEraseBlockSize-1))
386 return KErrArgument; // start position must be on erase block boundary
387 __ASSERT_ALWAYS(iState==EIdle,FLASH_FAULT());
393 void DMediaDriverFlashWin32::StartTimer(TInt aMicros)
395 aMicros += iTimerExtra - (iTickPeriod>>1);
398 iTimerExtra = aMicros + (iTickPeriod>>1);
399 iEventDfc.Enque(); // go off 'immediately'
404 iTimer.OneShot(aMicros / iTickPeriod);
408 void DMediaDriverFlashWin32::TimerFn(TAny* aPtr)
410 ((DMediaDriverFlashWin32*)aPtr)->iEventDfc.Add();
413 void DMediaDriverFlashWin32::EventDfc(TAny* aPtr)
415 ((DMediaDriverFlashWin32*)aPtr)->HandleEvent();
418 void DMediaDriverFlashWin32::HandleEvent()
420 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Event %d", iState));
424 case EWriting: // write completed
427 if(iCtrlIoState==ECtrlIoTimeOutPrep)
431 Complete(EReqWrite,KErrNotReady);
438 case EEraseNoSuspend:
441 if(iCtrlIoState==ECtrlIoTimeOutPrep)
445 Complete(EReqErase,KErrNotReady);
450 TInt remain = iEraseCounter - NKern::TickCount();
456 StartTimer(remain * iTickPeriod);
466 case EErase: // erase completed
469 case ESuspendPending:
470 if (TInt(iEraseCounter - NKern::TickCount()) <= 0)
479 __KTRACE_OPT(KPANIC,Kern::Printf("iState=%d",iState));
484 void DMediaDriverFlashWin32::StartErase()
486 // Continue an erase - iEraseCounter has the remaining time for the erase
489 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:StartErase %08x",iBase+iErasePos));
493 iState = EErasePending;
494 StartTimer(iResumeTime);
496 case EIdle: // starting to erase
497 iEraseCounter = iEraseTime;
500 iState = EEraseNoSuspend;
501 TUint32 remain = iEraseCounter;
502 iEraseCounter = NKern::TickCount() + remain/iTickPeriod;
503 StartTimer(Min(remain, iSuspendHoldOffTime));
507 __KTRACE_OPT(KPANIC,Kern::Printf("iState=%d",iState));
512 void DMediaDriverFlashWin32::SuspendErase()
514 __ASSERT_ALWAYS(iState==EErase || iState==ESuspendPending,FLASH_FAULT());
515 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendErase %08x",iBase+iErasePos));
517 TInt remain = Max(0, TInt(iEraseCounter - NKern::TickCount()));
518 iEraseCounter = remain * iTickPeriod;
519 iState = ESuspending;
523 void DMediaDriverFlashWin32::CompleteSuspend()
525 // erase suspend completion
526 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendComplete"));
529 // start any pending read or write requests
533 void DMediaDriverFlashWin32::CompleteErase()
535 // Do the actual erase in the completion
539 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:EraseComplete"));
541 memset(iBase + iErasePos, 0xff, iEraseBlockSize);
543 // complete the erase request
545 Complete(EReqErase,KErrNone);
547 // start any pending read or write requests
552 void DMediaDriverFlashWin32::StartPendingRW()
554 // start any pending read or write requests
562 // Override the base class version in order to provide access to ControlIO
564 TInt DMediaDriverFlashWin32::Request(TLocDrvRequest& m)
568 __KTRACE_OPT(KLOCDRV,Kern::Printf(">DMediaDriverFlashWin32::Request %d",id));
569 if (id!=DLocalDrive::EControlIO)
571 r=DMediaDriverFlash::Request(m);
574 r=ControlIO((TInt)m.iArg[0],m.iArg[1],m.iArg[2]);
575 DMediaDriver::Complete(m,r);
579 TInt DMediaDriverFlashWin32::ControlIO(TInt aCommand,TAny* /*aParam1*/,TAny* /*aParam2*/)
583 case(KCtrlIoTimeout):
585 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoControlIO invoked for KCtrlIoTimeout"));
586 // The aim of this test is simulate a flash timeout (and so exercise the consequent
587 // actions of the software that initiated the request)
588 if(iCtrlIoState!=EIdle)
590 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash: ControlIO request before previous completed"));
591 return KErrServerBusy;
595 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash: ControlIO timeout initiated"));
596 iCtrlIoState=ECtrlIoTimeOutPrep;
603 __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash: ERROR - unrecognised ControlIO command %d",aCommand));
613 TInt DMediaDriverFlashWin32::Caps(TLocalDriveCapsV2& aCaps)
614 // On return, aCaps data contains capability information about the
615 // flash device, in the form of a class derived from TLocalDriveCapsV2.
616 // The size of the derived class should not exceed KMaxLocalDriveCapsLength
617 // which is defined and used in e32\drivers\locmedia\locmedia.cpp. If a
618 // larger sized capabilities class is used, and this code is modified to
619 // write to member data beyond KMaxLocalDriveCapsLength this will cause a
622 // Invoke the base class method then update the sizes for
623 // Control Mode and Object Mode as required.
624 DMediaDriverFlash::Caps(aCaps);
625 #if defined (M18_EMULATION)
626 TLocalDriveCapsV7* caps = &((TLocalDriveCapsV7&)(aCaps));
627 caps->iControlModeSize=16;
628 caps->iObjectModeSize=1024;
629 __KTRACE_OPT( KLOCDRV, Kern::Printf("MLFS: ) ControlModeSize UPDATED as=0x%x", caps->iControlModeSize) );
630 __KTRACE_OPT( KLOCDRV, Kern::Printf("MLFS: ) ObjectModeSize UPDATED as=0x%x", caps->iObjectModeSize) );
632 return KErrCompletion; // synchronous completion
635 DMediaDriverFlash* DMediaDriverFlash::New(TInt aDevice)
637 return new DMediaDriverFlashWin32(aDevice);