--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bsptemplate/asspandvariant/template_variant/specific/lffsdev.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,668 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// template\Template_Variant\Specific\lffsdev.cpp
+// Implementation of a Logging Flash file system (LFFS) physical device driver
+// for a standard Common Flash Interface (CFI) based NOR flash chip.
+// This file is part of the Template Base port
+// N.B. This sample code assumes that:
+// (1) the device does not provide an interrupt i.e. it needs to be polled using a timer
+// to ascertain when an Erase/Write operation has completed.
+// (2) the flash chip does not have 'read-while-write' support.
+//
+//
+
+#include "lffsdev.h"
+#include "variant.h"
+
+#ifdef _DEBUG
+#define CHANGE_ERASE_STATE(x) {TUint32 s=iEraseState; iEraseState=x; __KTRACE_OPT(KLOCDRV,Kern::Printf("ErSt: %d->%d",s,x));}
+#else
+#define CHANGE_ERASE_STATE(x) iEraseState=x
+#endif
+
+//
+// TO DO: (mandatory)
+//
+// Define the pyhsical base address of the NOR-Flash
+// This is only example code... you will need to modify it for your hardware
+const TPhysAddr KFlashPhysicalBaseAddress = 0x04000000;
+
+
+/********************************************
+ * Common Flash Interface (CFI) query stuff
+ ********************************************/
+
+/**
+Read an 8-bit value from the device at the specified offset
+
+@param aOffset the address in device words
+*/
+TUint32 DMediaDriverFlashTemplate::ReadQueryData8(TUint32 aOffset)
+ {
+ volatile TUint8* pF=(volatile TUint8*)(iBase+FLASH_ADDRESS_IN_BYTES(aOffset));
+ return pF[0];
+ }
+
+/**
+Read a 16-bit value from the device at the specified offset
+
+@param aOffset the address in device words
+*/
+TUint32 DMediaDriverFlashTemplate::ReadQueryData16(TUint32 aOffset)
+ {
+ volatile TUint8* pF=(volatile TUint8*)(iBase);
+ return
+ pF[FLASH_ADDRESS_IN_BYTES(aOffset+0)] |
+ (pF[FLASH_ADDRESS_IN_BYTES(aOffset+1)] << 8);
+ }
+
+/**
+ Put the device into query mode to read the flash parameters.
+ */
+void DMediaDriverFlashTemplate::ReadFlashParameters()
+ {
+ volatile TFLASHWORD* pF=(volatile TFLASHWORD*)iBase + KCmdReadQueryOffset;
+ *pF=KCmdReadQuery;
+
+ TUint32 qd=ReadQueryData16(KQueryOffsetQRY)|(ReadQueryData8(KQueryOffsetQRY+2)<<16);
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query QRY=%08x",qd));
+ __ASSERT_ALWAYS(qd==0x595251,FLASH_FAULT());
+
+ qd = FLASH_BUS_DEVICES << ReadQueryData8(KQueryOffsetSizePower);
+
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query Size=%08x",qd));
+ iTotalSize=qd;
+
+ qd = FLASH_BUS_DEVICES << ReadQueryData16(KQueryOffsetWriteBufferSizePower);
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query WBSize=%08x",qd));
+ iWriteBufferSize=qd;
+
+ qd = (ReadQueryData16(KQueryOffsetEraseBlockSize)) << (8 + FLASH_BUS_DEVICES-1);
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query EBSize=%08x",qd));
+ iEraseBlockSize=qd;
+
+ *pF=KCmdReadArray;
+ }
+
+
+/********************************************
+ * Common Flash Interface (CFI) main code
+ ********************************************/
+
+/**
+NOR flash LFFS constructor.
+
+@param aMediaId Media id number from ELOCD
+*/
+DMediaDriverFlashTemplate::DMediaDriverFlashTemplate(TInt aMediaId)
+ : DMediaDriverFlash(aMediaId),
+ iHoldOffTimer(HoldOffTimerFn,this),
+ iEventDfc(EventDfc,this,NULL,2)
+ {
+ // iWriteState = EWriteIdle;
+ // iEraseState = EEraseIdle;
+ }
+
+/**
+Device specific implementation of the NOR LFFS initialisation routine.
+
+@see DMediaDriverFlash::Initialise
+@return KErrNone unless the write data buffer couldn't be allocated or the
+ timer interrupt could not be bound.
+ */
+TInt DMediaDriverFlashTemplate::Initialise()
+ {
+ iEventDfc.SetDfcQ(iPrimaryMedia->iDfcQ);
+ iData=(TUint8*)Kern::Alloc(KDataBufSize);
+ if (!iData)
+ return KErrNoMemory;
+
+ // Create temporary HW chunk to read FLASH device parameters (especially size)
+ DPlatChunkHw* pC = NULL;
+ TInt r = DPlatChunkHw::New(pC, KFlashPhysicalBaseAddress, 0x1000, EMapAttrSupRw|EMapAttrFullyBlocking);
+ if (r!=KErrNone)
+ return r;
+ iBase = pC->LinearAddress();
+ ReadFlashParameters();
+ // close temporary chunk and open chunk with correct size
+ pC->Close(NULL);
+ r = DPlatChunkHw::New(iFlashChunk, KFlashPhysicalBaseAddress, iTotalSize, EMapAttrSupRw|EMapAttrFullyBlocking);
+ if (r!=KErrNone)
+ return r;
+ iBase = iFlashChunk->LinearAddress();
+
+ r=Interrupt::Bind(KIntIdTimer1, Isr, this);
+ if (r!=KErrNone)
+ {
+ __KTRACE_OPT(KLOCDRV, Kern::Printf("Flash:Isr Bind failed"));
+ return r;
+ }
+
+ // TO DO: (mandatory)
+ // Write to the appropriate hardware register(s) to
+ // configure (if necessary) and enable the timer hardware
+ //
+
+ // Enable the timer interrupt
+ Interrupt::Enable(KIntIdTimer1);
+
+ return KErrNone;
+ }
+
+/**
+Used by the generic flash media driver code to get the erase block size in
+bytes.
+ */
+TUint32 DMediaDriverFlashTemplate::EraseBlockSize()
+ {
+ return iEraseBlockSize;
+ }
+
+/**
+@return Return size of lffs in bytes
+*/
+TUint32 DMediaDriverFlashTemplate::TotalSize()
+ {
+ return iTotalSize;
+ }
+
+/**
+Read at the location indicated by DMediaDriverFlash::iReadReq.
+Where Pos() is the read location
+
+@return >0 Defer request to ELOCD. A write is in progress
+@return KErrNone Erase has been started
+@return <0 An error has occured.
+*/
+TInt DMediaDriverFlashTemplate::DoRead()
+ {
+ if (iWriteReq)
+ return KMediaDriverDeferRequest; // write in progress so defer read
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoRead"));
+ if (iEraseState==EEraseIdle || iEraseState==ESuspended)
+ {
+ // can do the read now
+ TInt pos=(TInt)iReadReq->Pos();
+ TInt len=(TInt)iReadReq->Length();
+
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoRead ibase: %x, pos: %x, len: %x",iBase,pos,len));
+
+ // Issue a read array command
+ // Porting note: Some devices may work without this step.
+ // Ensure that the write is always dword aligned
+ volatile TFLASHWORD* pF=(volatile TFLASHWORD*)((iBase+pos)&0xFFFFFFF0);
+ *pF=KCmdReadArray;
+
+ TPtrC8 des((const TUint8*)(iBase+pos),len);
+ TInt r=iReadReq->WriteRemote(&des,0);
+ Complete(EReqRead,r);
+
+ // resume erase if necessary
+ if (iEraseState==ESuspended)
+ StartErase();
+ }
+ else if (iEraseState==EErase)
+ {
+ // erase in progress - suspend it
+ SuspendErase();
+ }
+ else if (iEraseState==EEraseNoSuspend)
+ CHANGE_ERASE_STATE(ESuspendPending); // wait for suspend to complete
+
+
+ return KErrNone;
+ }
+
+/**
+Write at the location indicated by DMediaDriverFlash::iWriteReq
+
+@return >0 Defer request to ELOCD. A read is in progress
+@return KErrNone Erase has been started
+@return <0 An error has occured.
+ */
+TInt DMediaDriverFlashTemplate::DoWrite()
+ {
+ if (iReadReq)
+ return KMediaDriverDeferRequest; // read in progress so defer write
+
+ TInt pos=(TInt)iWriteReq->Pos();
+ TInt len=(TInt)iWriteReq->Length();
+ if (len==0)
+ return KErrCompletion;
+ TUint32 wb_mask=iWriteBufferSize-1;
+ iWritePos=pos & ~wb_mask; // round media position down to write buffer boundary
+ TInt wb_off=pos & wb_mask; // how many bytes of padding at beginning
+ TInt start_len=Min(len,KDataBufSize-(TInt)wb_off);
+ TInt write_len=(start_len+wb_off+wb_mask)&~wb_mask;
+ memset(iData,0xff,iWriteBufferSize);
+ memset(iData+write_len-iWriteBufferSize,0xff,iWriteBufferSize);
+ TPtr8 des(iData+wb_off,0,start_len);
+ TInt r=iWriteReq->ReadRemote(&des,0);
+ if (r!=KErrNone)
+ return r;
+ iWriteReq->RemoteDesOffset()+=start_len;
+ iWriteReq->Length()-=start_len;
+ iDataBufPos=0;
+ iDataBufRemain=write_len;
+ iWriteError=KErrNone;
+
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Write iWritePos=%08x iDataBufRemain=%x",iWritePos,iDataBufRemain));
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Write Pos=%08x Length=%08x RemDesOff=%08x",
+ (TInt)iWriteReq->Pos(),(TInt)iWriteReq->Length(),iWriteReq->RemoteDesOffset()));
+
+ if (iEraseState==EEraseIdle || iEraseState==ESuspended)
+ {
+ // can start the write now
+ iWriteState=EWriting;
+ WriteStep();
+ }
+ else if (iEraseState==EErase)
+ {
+ // erase in progress - suspend it
+ SuspendErase();
+ }
+ else if (iEraseState==EEraseNoSuspend)
+ CHANGE_ERASE_STATE(ESuspendPending); // wait for suspend to complete
+
+ return KErrNone;
+ }
+
+void DMediaDriverFlashTemplate::WriteStep()
+ {
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:WriteStep @%08x",iWritePos));
+ if (iDataBufRemain)
+ {
+ // still data left in buffer
+ volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iWritePos);
+ TInt i=KMaxWriteSetupAttempts;
+ *pF=KCmdClearStatusRegister;
+ TUint32 s=0;
+ for (; i>0 && ((s&KStsReady)!=KStsReady); --i)
+ {
+ *pF=KCmdWriteToBuffer; // send write command
+ *pF=KCmdReadStatusRegister; // send read status command
+ s=*pF; // read status reg
+ }
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("i=%d, s=%08x",i,s));
+
+ // calculate the buffer size in words -1
+ TFLASHWORD l = (FLASH_BYTES_TO_WORDS(iWriteBufferSize)) - 1;
+
+#if FLASH_BUS_DEVICES == 2 // 2x16bit or 2x8bit devices
+ l|= l<< BUS_WIDTH_PER_DEVICE;
+#elif FLASH_BUS_DEVICES == 4 // 4x8bit device
+ l|= (l<<BUS_WIDTH_PER_DEVICE) | (l<<BUS_WIDTH_PER_DEVICE*2) (l<<BUS_WIDTH_PER_DEVICE*3);
+#endif
+
+ // write the data length in words to the device(s)
+ *pF=l;
+
+ const TFLASHWORD* pS=(const TFLASHWORD*)(iData+iDataBufPos);
+
+ // write the data
+ TInt len;
+ for (len = l; len>=0; len--)
+ {
+ *pF++=*pS++;
+ }
+
+ *(volatile TFLASHWORD *)(iBase+iWritePos) = KCmdConfirm;
+
+ // set up timer to poll for completion
+ StartPollTimer(KFlashWriteTimerPeriod,KFlashWriteTimerRetries);
+
+ iWritePos+=iWriteBufferSize;
+ iDataBufPos+=iWriteBufferSize;
+ iDataBufRemain-=iWriteBufferSize;
+ if (!iDataBufRemain)
+ {
+ // refill buffer
+ TInt len=(TInt)iWriteReq->Length();
+ if (!len)
+ return; // all data has been written, complete request next time
+ TUint32 wb_mask=iWriteBufferSize-1;
+ TInt block_len=Min(len,KDataBufSize);
+ TInt write_len=(block_len+wb_mask)&~wb_mask;
+ memset(iData+write_len-iWriteBufferSize,0xff,iWriteBufferSize);
+ TPtr8 des(iData,0,block_len);
+ TInt r=iWriteReq->ReadRemote(&des,0);
+ if (r!=KErrNone)
+ {
+ iWriteError=r;
+ return; // leave iDataBufRemain=0 so request is terminated when write completes
+ }
+ iWriteReq->RemoteDesOffset()+=block_len;
+ iWriteReq->Length()-=block_len;
+ iDataBufPos=0;
+ iDataBufRemain=write_len;
+ }
+ }
+ else
+ {
+ // write request should have completed, maybe with an error
+ __ASSERT_ALWAYS(iWriteReq->Length()==0 || iWriteError,FLASH_FAULT());
+ iWriteState=EWriteIdle;
+ Complete(EReqWrite,iWriteError);
+ if (iEraseState==ESuspended)
+ StartErase();
+ }
+ }
+
+/**
+Erase at the location indicated by DMediaDriverFlash::iEraseReq
+
+@return >0 Defer request to ELOCD. Read or a write is in progress
+@return KErrNone Erase has been started
+@return <0 An error has occured.
+ */
+TInt DMediaDriverFlashTemplate::DoErase()
+ {
+ if (iReadReq || iWriteReq)
+ return KMediaDriverDeferRequest; // read or write in progress so defer this request
+ TUint32 pos=(TUint32)iEraseReq->Pos();
+ TUint32 len=(TUint32)iEraseReq->Length();
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoErase %d@%08x",len,pos));
+ if (len!=iEraseBlockSize)
+ return KErrArgument; // only allow single-block erase
+ if (pos & (iEraseBlockSize-1))
+ return KErrArgument; // start position must be on erase block boundary
+ iErasePos=pos;
+ __ASSERT_ALWAYS(iEraseState==EEraseIdle,FLASH_FAULT());
+ StartErase();
+ return KErrNone;
+ }
+
+void DMediaDriverFlashTemplate::StartHoldOffTimer()
+ {
+ // if this is a retry, don't allow suspends
+ if (iEraseAttempt==0)
+ iHoldOffTimer.OneShot(KEraseSuspendHoldOffTime);
+ }
+
+void DMediaDriverFlashTemplate::CancelHoldOffTimer()
+ {
+ iHoldOffTimer.Cancel();
+ ClearEvents(EHoldOffEnd);
+ }
+
+void DMediaDriverFlashTemplate::ClearEvents(TUint32 aEvents)
+ {
+ __e32_atomic_and_ord32(&iEvents, ~aEvents);
+ }
+
+void DMediaDriverFlashTemplate::HoldOffTimerFn(TAny* aPtr)
+ {
+ DMediaDriverFlashTemplate* p=(DMediaDriverFlashTemplate*)aPtr;
+ p->IPostEvents(EHoldOffEnd);
+ }
+
+void DMediaDriverFlashTemplate::StartPollTimer(TUint32 aPeriod, TUint32 aRetries)
+ {
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Tmr %d * %d",aPeriod,aRetries));
+
+ ClearEvents(EPollTimer);
+ iPollPeriod=aPeriod;
+ iPollRetries=aRetries;
+ StartPollTimer();
+ }
+
+void DMediaDriverFlashTemplate::StartPollTimer()
+ {
+ // TO DO: (mandatory)
+ // Configure the hardware timer to expire after iPollPeriod ticks
+ // and start the timer
+
+ }
+
+void DMediaDriverFlashTemplate::EventDfc(TAny* aPtr)
+ {
+ DMediaDriverFlashTemplate* p=(DMediaDriverFlashTemplate*)aPtr;
+ TUint32 e = __e32_atomic_swp_ord32(&p->iEvents, 0);
+ if (e)
+ p->HandleEvents(e);
+ }
+
+void DMediaDriverFlashTemplate::HandleEvents(TUint32 aEvents)
+ {
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Events %x",aEvents));
+ if (aEvents & EHoldOffEnd)
+ {
+ if (iEraseState==ESuspendPending)
+ {
+ SuspendErase();
+ }
+ else if (iEraseState==EEraseNoSuspend)
+ {
+ CHANGE_ERASE_STATE(EErase); // can now be suspended
+ }
+ else
+ {
+ __KTRACE_OPT(KPANIC,Kern::Printf("iEraseState=%d",iEraseState));
+ FLASH_FAULT();
+ }
+ }
+ if (aEvents & EPollTimer)
+ {
+ volatile TFLASHWORD* pF=(volatile TFLASHWORD*)iBase;
+ *pF=KCmdReadStatusRegister;
+ if ((*pF & KStsReady)!=KStsReady)
+ {
+ // not ready yet
+ if (--iPollRetries)
+ {
+ // try again
+ StartPollTimer();
+ }
+ else
+ // timed out
+ aEvents|=ETimeout;
+ }
+ else
+ {
+ // ready
+ TFLASHWORD s=*pF; // read full status value
+ *pF=KCmdClearStatusRegister;
+ DoFlashReady(s);
+ }
+ }
+ if (aEvents & ETimeout)
+ {
+ DoFlashTimeout();
+ }
+ }
+
+void DMediaDriverFlashTemplate::StartErase()
+ {
+ TFLASHWORD s=KStsReady;
+ TInt i;
+ volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:StartErase %08x",pF));
+ switch (iEraseState)
+ {
+ case EEraseIdle: // first attempt to erase
+ iEraseAttempt=-1;
+ // coverity[fallthrough]
+ // fallthrough after attempt
+ case EErase: // retry after verify failed
+ case EEraseNoSuspend:
+ ++iEraseAttempt;
+ *pF=KCmdBlockErase;
+ *pF=KCmdConfirm;
+ CHANGE_ERASE_STATE(EEraseNoSuspend);
+ iEraseError=0;
+ StartHoldOffTimer();
+ break;
+ case ESuspended:
+ *pF=KCmdClearStatusRegister;
+ *pF=KCmdEraseResume;
+ CHANGE_ERASE_STATE(EEraseNoSuspend);
+ i=KMaxEraseResumeAttempts;
+ for (; i>0 && ((s&KStsReady)!=0); --i)
+ {
+ *pF=KCmdReadStatusRegister; // send read status command
+ s=*pF; // read status reg
+ s=*pF; // read status reg
+ }
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("RESUME: i=%d, s=%08x",i,s));
+ StartHoldOffTimer();
+ break;
+ default:
+ __KTRACE_OPT(KPANIC,Kern::Printf("iEraseState=%d",iEraseState));
+ FLASH_FAULT();
+ }
+ StartPollTimer(KFlashEraseTimerPeriod,KFlashEraseTimerRetries);
+ }
+
+void DMediaDriverFlashTemplate::SuspendErase()
+ {
+ __ASSERT_ALWAYS(iEraseState==EErase || iEraseState==ESuspendPending,FLASH_FAULT());
+ volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendErase %08x",pF));
+ *pF=KCmdEraseSuspend;
+ CHANGE_ERASE_STATE(ESuspending);
+ StartPollTimer(KFlashSuspendTimerPeriod,KFlashSuspendTimerRetries);
+ }
+
+void DMediaDriverFlashTemplate::StartPendingRW()
+ {
+ // start any pending read or write requests
+ if (iReadReq)
+ DoRead();
+ if (iWriteReq)
+ {
+ // can start the write now
+ iWriteState=EWriting;
+ WriteStep();
+ }
+ }
+
+void DMediaDriverFlashTemplate::DoFlashReady(TUint32 aStatus)
+ {
+ // could be write completion, erase completion or suspend completion
+ if (iWriteState==EWriting)
+ {
+ // write completion
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:WriteComplete %08x",aStatus));
+ TUint32 err=aStatus & (KStsWriteError|KStsVppLow|KStsLocked);
+ if (err)
+ {
+ iWriteState=EWriteIdle;
+ Complete(EReqWrite,KErrGeneral);
+ if (iEraseState==ESuspended)
+ StartErase();
+ }
+ else
+ WriteStep();
+ return;
+ }
+
+ // put the FLASH back into read mode
+ volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
+ *pF=KCmdReadArray;
+
+ if (iEraseState==ESuspending)
+ {
+ // erase suspend completion
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendComplete %08x",aStatus));
+
+ // accumulate errors during erase
+ iEraseError|=(aStatus & (KStsEraseError|KStsVppLow|KStsLocked));
+
+ if (aStatus & KStsSuspended)
+ {
+ // at least one of the two FLASH devices has suspended
+ CHANGE_ERASE_STATE(ESuspended);
+
+ // start any pending read or write requests
+ StartPendingRW();
+ return; // in case erase has been resumed by DoRead()
+ }
+
+ // erase completed before we suspended it
+ CHANGE_ERASE_STATE(EErase);
+ }
+ if (iEraseState==EErase || iEraseState==EEraseNoSuspend)
+ {
+ // erase completion
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:EraseComplete %08x",aStatus));
+ CancelHoldOffTimer();
+
+ // accumulate errors during erase
+ iEraseError|=(aStatus & (KStsEraseError|KStsVppLow|KStsLocked));
+
+ TFLASHWORD x = FLASH_ERASE_WORD_VALUE;
+
+ // if no device error, verify that erase was successful
+ if (!iEraseError)
+ {
+ volatile TFLASHWORD* p=pF;
+ volatile TFLASHWORD* pE=p + FLASH_BYTES_TO_WORDS(iEraseBlockSize);
+ while(p<pE)
+ x&=*p++;
+ }
+ else
+ {
+ }
+ if (x == FLASH_ERASE_WORD_VALUE)
+ {
+ // erase OK
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:VerifyErase OK"));
+ CHANGE_ERASE_STATE(EEraseIdle);
+
+ // complete the erase request
+ TInt r=iEraseError?KErrGeneral:KErrNone;
+ Complete(EReqErase,r);
+
+ // start any pending read or write requests
+ StartPendingRW();
+ }
+ else
+ {
+ // erase failed, so retry
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:VerifyErase BAD"));
+ StartErase();
+ }
+ }
+ }
+
+void DMediaDriverFlashTemplate::DoFlashTimeout()
+ {
+ // TO DO: (optional)
+ // Take appropriate action to handle a timeout.
+ FLASH_FAULT(); // // EXAMPLE ONLY:
+ }
+
+DMediaDriverFlash* DMediaDriverFlash::New(TInt aMediaId)
+ {
+ return new DMediaDriverFlashTemplate(aMediaId);
+ }
+
+void DMediaDriverFlashTemplate::Isr(TAny* aPtr)
+ {
+ DMediaDriverFlashTemplate& d=*(DMediaDriverFlashTemplate*)aPtr;
+
+
+ // TO DO: (mandatory)
+ // Write to the timer hardware register(s) to
+ // clear the timer interrupt
+ //
+
+ d.IPostEvents(EPollTimer);
+ }
+
+void DMediaDriverFlashTemplate::IPostEvents(TUint32 aEvents)
+ {
+ iEvents|=aEvents;
+ iEventDfc.Add();
+ }