bsptemplate/asspandvariant/template_variant/specific/lffsdev.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2004-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 // template\Template_Variant\Specific\lffsdev.cpp
       
    15 // Implementation of a Logging Flash file system (LFFS) physical device driver 
       
    16 // for a standard Common Flash Interface (CFI) based NOR flash chip.
       
    17 // This file is part of the Template Base port
       
    18 // N.B. This sample code assumes that:
       
    19 // (1)	the device does not provide an interrupt i.e. it needs to be polled using a timer 
       
    20 // to ascertain when an Erase/Write operation has completed.
       
    21 // (2) the flash chip does not have 'read-while-write' support.
       
    22 // 
       
    23 //
       
    24 
       
    25 #include "lffsdev.h"
       
    26 #include "variant.h"
       
    27 
       
    28 #ifdef _DEBUG
       
    29 #define CHANGE_ERASE_STATE(x)	{TUint32 s=iEraseState; iEraseState=x; __KTRACE_OPT(KLOCDRV,Kern::Printf("ErSt: %d->%d",s,x));}
       
    30 #else
       
    31 #define CHANGE_ERASE_STATE(x)	iEraseState=x
       
    32 #endif
       
    33 
       
    34 //
       
    35 // TO DO: (mandatory)
       
    36 //
       
    37 // Define the pyhsical base address of the NOR-Flash
       
    38 // This is only example code... you will need to modify it for your hardware
       
    39 const TPhysAddr KFlashPhysicalBaseAddress = 0x04000000;
       
    40 
       
    41 
       
    42 /********************************************
       
    43  * Common Flash Interface (CFI) query stuff
       
    44  ********************************************/
       
    45 
       
    46 /**
       
    47 Read an 8-bit value from the device at the specified offset
       
    48 
       
    49 @param	aOffset	the address in device words 
       
    50 */
       
    51 TUint32 DMediaDriverFlashTemplate::ReadQueryData8(TUint32 aOffset)
       
    52 	{
       
    53 	volatile TUint8* pF=(volatile TUint8*)(iBase+FLASH_ADDRESS_IN_BYTES(aOffset));
       
    54 	return pF[0];
       
    55 	}
       
    56 
       
    57 /**
       
    58 Read a 16-bit value from the device at the specified offset
       
    59 
       
    60 @param	aOffset	the address in device words 
       
    61 */
       
    62 TUint32 DMediaDriverFlashTemplate::ReadQueryData16(TUint32 aOffset)
       
    63 	{
       
    64 	volatile TUint8* pF=(volatile TUint8*)(iBase);
       
    65 	return 
       
    66 		 pF[FLASH_ADDRESS_IN_BYTES(aOffset+0)] | 
       
    67 		(pF[FLASH_ADDRESS_IN_BYTES(aOffset+1)] << 8);
       
    68 	}
       
    69 
       
    70 /**
       
    71  Put the device into query mode to read the flash parameters.
       
    72  */
       
    73 void DMediaDriverFlashTemplate::ReadFlashParameters()
       
    74 	{
       
    75 	volatile TFLASHWORD* pF=(volatile TFLASHWORD*)iBase + KCmdReadQueryOffset;
       
    76 	*pF=KCmdReadQuery;
       
    77 
       
    78 	TUint32 qd=ReadQueryData16(KQueryOffsetQRY)|(ReadQueryData8(KQueryOffsetQRY+2)<<16);
       
    79 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query QRY=%08x",qd));
       
    80 	__ASSERT_ALWAYS(qd==0x595251,FLASH_FAULT());
       
    81 
       
    82 	qd = FLASH_BUS_DEVICES << ReadQueryData8(KQueryOffsetSizePower);
       
    83 
       
    84 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query Size=%08x",qd));
       
    85 	iTotalSize=qd;
       
    86 
       
    87 	qd = FLASH_BUS_DEVICES << ReadQueryData16(KQueryOffsetWriteBufferSizePower);
       
    88 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query WBSize=%08x",qd));
       
    89 	iWriteBufferSize=qd;
       
    90 
       
    91 	qd = (ReadQueryData16(KQueryOffsetEraseBlockSize)) << (8 + FLASH_BUS_DEVICES-1);
       
    92 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Query EBSize=%08x",qd));
       
    93 	iEraseBlockSize=qd;
       
    94 
       
    95 	*pF=KCmdReadArray;
       
    96 	}
       
    97 
       
    98 
       
    99 /********************************************
       
   100  * Common Flash Interface (CFI) main code
       
   101  ********************************************/
       
   102 
       
   103 /**
       
   104 NOR flash LFFS constructor.
       
   105 
       
   106 @param aMediaId            Media id number from ELOCD
       
   107 */
       
   108 DMediaDriverFlashTemplate::DMediaDriverFlashTemplate(TInt aMediaId)
       
   109 	:	DMediaDriverFlash(aMediaId),
       
   110 		iHoldOffTimer(HoldOffTimerFn,this),
       
   111 		iEventDfc(EventDfc,this,NULL,2)
       
   112 	{
       
   113 	// iWriteState = EWriteIdle;
       
   114 	// iEraseState = EEraseIdle;
       
   115 	}
       
   116 
       
   117 /**
       
   118 Device specific implementation of the NOR LFFS initialisation routine.
       
   119 
       
   120 @see DMediaDriverFlash::Initialise
       
   121 @return KErrNone unless the write data buffer couldn't be allocated or the
       
   122          timer interrupt could not be bound.
       
   123  */
       
   124 TInt DMediaDriverFlashTemplate::Initialise()
       
   125 	{
       
   126 	iEventDfc.SetDfcQ(iPrimaryMedia->iDfcQ);
       
   127 	iData=(TUint8*)Kern::Alloc(KDataBufSize);
       
   128 	if (!iData)
       
   129 		return KErrNoMemory;
       
   130 
       
   131 	// Create temporary HW chunk to read FLASH device parameters (especially size)
       
   132 	DPlatChunkHw* pC = NULL;
       
   133 	TInt r = DPlatChunkHw::New(pC, KFlashPhysicalBaseAddress, 0x1000, EMapAttrSupRw|EMapAttrFullyBlocking);
       
   134 	if (r!=KErrNone)
       
   135 		return r;
       
   136 	iBase = pC->LinearAddress();
       
   137 	ReadFlashParameters();
       
   138 	// close temporary chunk and open chunk with correct size
       
   139 	pC->Close(NULL);
       
   140 	r = DPlatChunkHw::New(iFlashChunk, KFlashPhysicalBaseAddress, iTotalSize, EMapAttrSupRw|EMapAttrFullyBlocking);
       
   141 	if (r!=KErrNone)
       
   142 		return r;
       
   143 	iBase = iFlashChunk->LinearAddress();
       
   144 
       
   145 	r=Interrupt::Bind(KIntIdTimer1, Isr, this);
       
   146 	if (r!=KErrNone)
       
   147 		{
       
   148 		__KTRACE_OPT(KLOCDRV, Kern::Printf("Flash:Isr Bind failed"));
       
   149 		return r;
       
   150 		}
       
   151 
       
   152 	// TO DO: (mandatory)
       
   153 	// Write to the appropriate hardware register(s) to
       
   154 	// configure (if necessary) and enable the timer hardware
       
   155 	//
       
   156 
       
   157 	// Enable the timer interrupt
       
   158 	Interrupt::Enable(KIntIdTimer1);
       
   159 	
       
   160 	return KErrNone;
       
   161 	}
       
   162 
       
   163 /**
       
   164 Used by the generic flash media driver code to get the erase block size in
       
   165 bytes. 
       
   166  */
       
   167 TUint32 DMediaDriverFlashTemplate::EraseBlockSize()
       
   168 	{
       
   169 	return iEraseBlockSize;
       
   170 	}
       
   171 
       
   172 /**
       
   173 @return Return size of lffs in bytes
       
   174 */
       
   175 TUint32 DMediaDriverFlashTemplate::TotalSize()
       
   176 	{
       
   177 	return iTotalSize;
       
   178 	}
       
   179 
       
   180 /**
       
   181 Read at the location indicated by DMediaDriverFlash::iReadReq. 
       
   182 Where Pos() is the read location
       
   183 
       
   184 @return >0			Defer request to ELOCD. A write is in progress
       
   185 @return KErrNone	Erase has been started
       
   186 @return <0			An error has occured.
       
   187 */
       
   188 TInt DMediaDriverFlashTemplate::DoRead()
       
   189 	{
       
   190 	if (iWriteReq)
       
   191 		return KMediaDriverDeferRequest;	// write in progress so defer read
       
   192 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoRead"));
       
   193 	if (iEraseState==EEraseIdle || iEraseState==ESuspended)
       
   194 		{
       
   195 		// can do the read now
       
   196 		TInt pos=(TInt)iReadReq->Pos();
       
   197 		TInt len=(TInt)iReadReq->Length();
       
   198 
       
   199 		__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoRead ibase: %x, pos: %x, len: %x",iBase,pos,len));
       
   200 
       
   201 		// Issue a read array command
       
   202 		// Porting note: Some devices may work without this step.
       
   203 		// Ensure that the write is always dword aligned
       
   204 		volatile TFLASHWORD* pF=(volatile TFLASHWORD*)((iBase+pos)&0xFFFFFFF0);
       
   205 		*pF=KCmdReadArray;
       
   206 
       
   207 		TPtrC8 des((const TUint8*)(iBase+pos),len);
       
   208 		TInt r=iReadReq->WriteRemote(&des,0);
       
   209 		Complete(EReqRead,r);
       
   210 
       
   211 		// resume erase if necessary
       
   212 		if (iEraseState==ESuspended)
       
   213 			StartErase();
       
   214 		}
       
   215 	else if (iEraseState==EErase)
       
   216 		{
       
   217 		// erase in progress - suspend it
       
   218 		SuspendErase();
       
   219 		}
       
   220 	else if (iEraseState==EEraseNoSuspend)
       
   221 		CHANGE_ERASE_STATE(ESuspendPending);	// wait for suspend to complete
       
   222 	
       
   223 	
       
   224 	return KErrNone;
       
   225 	}
       
   226 
       
   227 /**
       
   228 Write at the location indicated by DMediaDriverFlash::iWriteReq
       
   229 
       
   230 @return >0			Defer request to ELOCD. A read is in progress
       
   231 @return KErrNone	Erase has been started
       
   232 @return <0			An error has occured.
       
   233  */
       
   234 TInt DMediaDriverFlashTemplate::DoWrite()
       
   235 	{
       
   236 	if (iReadReq)
       
   237 		return KMediaDriverDeferRequest;	// read in progress so defer write
       
   238 
       
   239 	TInt pos=(TInt)iWriteReq->Pos();
       
   240 	TInt len=(TInt)iWriteReq->Length();
       
   241 	if (len==0)
       
   242 		return KErrCompletion;
       
   243 	TUint32 wb_mask=iWriteBufferSize-1;
       
   244 	iWritePos=pos & ~wb_mask;	// round media position down to write buffer boundary
       
   245 	TInt wb_off=pos & wb_mask;	// how many bytes of padding at beginning
       
   246 	TInt start_len=Min(len,KDataBufSize-(TInt)wb_off);
       
   247 	TInt write_len=(start_len+wb_off+wb_mask)&~wb_mask;
       
   248 	memset(iData,0xff,iWriteBufferSize);
       
   249 	memset(iData+write_len-iWriteBufferSize,0xff,iWriteBufferSize);
       
   250 	TPtr8 des(iData+wb_off,0,start_len);
       
   251 	TInt r=iWriteReq->ReadRemote(&des,0);
       
   252 	if (r!=KErrNone)
       
   253 		return r;
       
   254 	iWriteReq->RemoteDesOffset()+=start_len;
       
   255 	iWriteReq->Length()-=start_len;
       
   256 	iDataBufPos=0;
       
   257 	iDataBufRemain=write_len;
       
   258 	iWriteError=KErrNone;
       
   259 
       
   260 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Write iWritePos=%08x iDataBufRemain=%x",iWritePos,iDataBufRemain));
       
   261 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Write Pos=%08x Length=%08x RemDesOff=%08x",
       
   262 										(TInt)iWriteReq->Pos(),(TInt)iWriteReq->Length(),iWriteReq->RemoteDesOffset()));
       
   263 
       
   264 	if (iEraseState==EEraseIdle || iEraseState==ESuspended)
       
   265 		{
       
   266 		// can start the write now
       
   267 		iWriteState=EWriting;
       
   268 		WriteStep();
       
   269 		}
       
   270 	else if (iEraseState==EErase)
       
   271 		{
       
   272 		// erase in progress - suspend it
       
   273 		SuspendErase();
       
   274 		}
       
   275 	else if (iEraseState==EEraseNoSuspend)
       
   276 		CHANGE_ERASE_STATE(ESuspendPending);	// wait for suspend to complete
       
   277 	
       
   278 	return KErrNone;
       
   279 	}
       
   280 
       
   281 void DMediaDriverFlashTemplate::WriteStep()
       
   282 	{
       
   283 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:WriteStep @%08x",iWritePos));
       
   284 	if (iDataBufRemain)
       
   285 		{
       
   286 		// still data left in buffer
       
   287 		volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iWritePos);
       
   288 		TInt i=KMaxWriteSetupAttempts;
       
   289 		*pF=KCmdClearStatusRegister;
       
   290 		TUint32 s=0;
       
   291 		for (; i>0 && ((s&KStsReady)!=KStsReady); --i)
       
   292 			{
       
   293 			*pF=KCmdWriteToBuffer;		// send write command
       
   294 			*pF=KCmdReadStatusRegister;	// send read status command
       
   295 			s=*pF;						// read status reg
       
   296 			}
       
   297 		__KTRACE_OPT(KLOCDRV,Kern::Printf("i=%d, s=%08x",i,s));
       
   298 
       
   299 		// calculate the buffer size in words -1 
       
   300 		TFLASHWORD l = (FLASH_BYTES_TO_WORDS(iWriteBufferSize)) - 1;
       
   301 
       
   302 #if FLASH_BUS_DEVICES == 2		// 2x16bit or 2x8bit devices
       
   303 		l|= l<< BUS_WIDTH_PER_DEVICE;
       
   304 #elif FLASH_BUS_DEVICES == 4	// 4x8bit device
       
   305 		l|= (l<<BUS_WIDTH_PER_DEVICE) | (l<<BUS_WIDTH_PER_DEVICE*2) (l<<BUS_WIDTH_PER_DEVICE*3);
       
   306 #endif
       
   307 
       
   308 		// write the data length in words to the device(s)
       
   309 		*pF=l;
       
   310 
       
   311 		const TFLASHWORD* pS=(const TFLASHWORD*)(iData+iDataBufPos);
       
   312 
       
   313 		// write the data
       
   314 		TInt len;
       
   315 		for (len = l; len>=0; len--)
       
   316 			{
       
   317 			*pF++=*pS++;
       
   318 			}
       
   319 	
       
   320 		*(volatile TFLASHWORD *)(iBase+iWritePos) = KCmdConfirm; 
       
   321 
       
   322 		// set up timer to poll for completion
       
   323 		StartPollTimer(KFlashWriteTimerPeriod,KFlashWriteTimerRetries);
       
   324 
       
   325 		iWritePos+=iWriteBufferSize;
       
   326 		iDataBufPos+=iWriteBufferSize;
       
   327 		iDataBufRemain-=iWriteBufferSize;
       
   328 		if (!iDataBufRemain)
       
   329 			{
       
   330 			// refill buffer
       
   331 			TInt len=(TInt)iWriteReq->Length();
       
   332 			if (!len)
       
   333 				return;	// all data has been written, complete request next time
       
   334 			TUint32 wb_mask=iWriteBufferSize-1;
       
   335 			TInt block_len=Min(len,KDataBufSize);
       
   336 			TInt write_len=(block_len+wb_mask)&~wb_mask;
       
   337 			memset(iData+write_len-iWriteBufferSize,0xff,iWriteBufferSize);
       
   338 			TPtr8 des(iData,0,block_len);
       
   339 			TInt r=iWriteReq->ReadRemote(&des,0);
       
   340 			if (r!=KErrNone)
       
   341 				{
       
   342 				iWriteError=r;
       
   343 				return;	// leave iDataBufRemain=0 so request is terminated when write completes
       
   344 				}
       
   345 			iWriteReq->RemoteDesOffset()+=block_len;
       
   346 			iWriteReq->Length()-=block_len;
       
   347 			iDataBufPos=0;
       
   348 			iDataBufRemain=write_len;
       
   349 			}
       
   350 		}
       
   351 	else
       
   352 		{
       
   353 		// write request should have completed, maybe with an error
       
   354 		__ASSERT_ALWAYS(iWriteReq->Length()==0 || iWriteError,FLASH_FAULT());
       
   355 		iWriteState=EWriteIdle;
       
   356 		Complete(EReqWrite,iWriteError);
       
   357 		if (iEraseState==ESuspended)
       
   358 			StartErase();
       
   359 		}
       
   360 	}
       
   361 
       
   362 /**
       
   363 Erase at the location indicated by DMediaDriverFlash::iEraseReq
       
   364 
       
   365 @return >0			Defer request to ELOCD. Read or a write is in progress
       
   366 @return KErrNone	Erase has been started
       
   367 @return <0			An error has occured.
       
   368  */
       
   369 TInt DMediaDriverFlashTemplate::DoErase()
       
   370 	{
       
   371 	if (iReadReq || iWriteReq)
       
   372 		return KMediaDriverDeferRequest;		// read or write in progress so defer this request
       
   373 	TUint32 pos=(TUint32)iEraseReq->Pos();
       
   374 	TUint32 len=(TUint32)iEraseReq->Length();
       
   375 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoErase %d@%08x",len,pos));
       
   376 	if (len!=iEraseBlockSize)
       
   377 		return KErrArgument;	// only allow single-block erase
       
   378 	if (pos & (iEraseBlockSize-1))
       
   379 		return KErrArgument;	// start position must be on erase block boundary
       
   380 	iErasePos=pos;
       
   381 	__ASSERT_ALWAYS(iEraseState==EEraseIdle,FLASH_FAULT());
       
   382 	StartErase();
       
   383 	return KErrNone;
       
   384 	}
       
   385 
       
   386 void DMediaDriverFlashTemplate::StartHoldOffTimer()
       
   387 	{
       
   388 	// if this is a retry, don't allow suspends
       
   389 	if (iEraseAttempt==0)
       
   390 		iHoldOffTimer.OneShot(KEraseSuspendHoldOffTime);
       
   391 	}
       
   392 
       
   393 void DMediaDriverFlashTemplate::CancelHoldOffTimer()
       
   394 	{
       
   395 	iHoldOffTimer.Cancel();
       
   396 	ClearEvents(EHoldOffEnd);
       
   397 	}
       
   398 
       
   399 void DMediaDriverFlashTemplate::ClearEvents(TUint32 aEvents)
       
   400 	{
       
   401 	__e32_atomic_and_ord32(&iEvents, ~aEvents);
       
   402 	}
       
   403 
       
   404 void DMediaDriverFlashTemplate::HoldOffTimerFn(TAny* aPtr)
       
   405 	{
       
   406 	DMediaDriverFlashTemplate* p=(DMediaDriverFlashTemplate*)aPtr;
       
   407 	p->IPostEvents(EHoldOffEnd);
       
   408 	}
       
   409 
       
   410 void DMediaDriverFlashTemplate::StartPollTimer(TUint32 aPeriod, TUint32 aRetries)
       
   411 	{
       
   412 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Tmr %d * %d",aPeriod,aRetries));
       
   413 
       
   414 	ClearEvents(EPollTimer);
       
   415 	iPollPeriod=aPeriod;
       
   416 	iPollRetries=aRetries;
       
   417 	StartPollTimer();
       
   418 	}
       
   419 
       
   420 void DMediaDriverFlashTemplate::StartPollTimer()
       
   421 	{
       
   422 	// TO DO: (mandatory)
       
   423 	// Configure the hardware timer to expire after iPollPeriod ticks
       
   424 	// and start the timer
       
   425 	
       
   426 	}
       
   427 
       
   428 void DMediaDriverFlashTemplate::EventDfc(TAny* aPtr)
       
   429 	{
       
   430 	DMediaDriverFlashTemplate* p=(DMediaDriverFlashTemplate*)aPtr;
       
   431 	TUint32 e = __e32_atomic_swp_ord32(&p->iEvents, 0);
       
   432 	if (e)
       
   433 		p->HandleEvents(e);
       
   434 	}
       
   435 
       
   436 void DMediaDriverFlashTemplate::HandleEvents(TUint32 aEvents)
       
   437 	{
       
   438 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Events %x",aEvents));
       
   439 	if (aEvents & EHoldOffEnd)
       
   440 		{
       
   441 		if (iEraseState==ESuspendPending)
       
   442 			{
       
   443 			SuspendErase();
       
   444 			}
       
   445 		else if (iEraseState==EEraseNoSuspend)
       
   446 			{
       
   447 			CHANGE_ERASE_STATE(EErase);	// can now be suspended
       
   448 			}
       
   449 		else
       
   450 			{
       
   451 			__KTRACE_OPT(KPANIC,Kern::Printf("iEraseState=%d",iEraseState));
       
   452 			FLASH_FAULT();
       
   453 			}
       
   454 		}
       
   455 	if (aEvents & EPollTimer)
       
   456 		{
       
   457 		volatile TFLASHWORD* pF=(volatile TFLASHWORD*)iBase;
       
   458 		*pF=KCmdReadStatusRegister;
       
   459 		if ((*pF & KStsReady)!=KStsReady)
       
   460 			{
       
   461 			// not ready yet
       
   462 			if (--iPollRetries)
       
   463 				{
       
   464 				// try again
       
   465 				StartPollTimer();
       
   466 				}
       
   467 			else
       
   468 				// timed out
       
   469 				aEvents|=ETimeout;
       
   470 			}
       
   471 		else
       
   472 			{
       
   473 			// ready
       
   474 			TFLASHWORD s=*pF;	// read full status value
       
   475 			*pF=KCmdClearStatusRegister;
       
   476 			DoFlashReady(s);
       
   477 			}
       
   478 		}
       
   479 	if (aEvents & ETimeout)
       
   480 		{
       
   481 		DoFlashTimeout();
       
   482 		}
       
   483 	}
       
   484 
       
   485 void DMediaDriverFlashTemplate::StartErase()
       
   486 	{
       
   487 	TFLASHWORD s=KStsReady;
       
   488 	TInt i;
       
   489 	volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
       
   490 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:StartErase %08x",pF));
       
   491 	switch (iEraseState)
       
   492 		{
       
   493 		case EEraseIdle:	// first attempt to erase
       
   494 			iEraseAttempt=-1;
       
   495 			// coverity[fallthrough]
       
   496 			// fallthrough after attempt
       
   497 		case EErase:	// retry after verify failed
       
   498 		case EEraseNoSuspend:
       
   499 			++iEraseAttempt;
       
   500 			*pF=KCmdBlockErase;
       
   501 			*pF=KCmdConfirm;
       
   502 			CHANGE_ERASE_STATE(EEraseNoSuspend);
       
   503 			iEraseError=0;
       
   504 			StartHoldOffTimer();
       
   505 			break;
       
   506 		case ESuspended:
       
   507 			*pF=KCmdClearStatusRegister;
       
   508 			*pF=KCmdEraseResume;
       
   509 			CHANGE_ERASE_STATE(EEraseNoSuspend);
       
   510 			i=KMaxEraseResumeAttempts;
       
   511 			for (; i>0 && ((s&KStsReady)!=0); --i)
       
   512 				{
       
   513 				*pF=KCmdReadStatusRegister;	// send read status command
       
   514 				s=*pF;						// read status reg
       
   515 				s=*pF;						// read status reg
       
   516 				}
       
   517 			__KTRACE_OPT(KLOCDRV,Kern::Printf("RESUME: i=%d, s=%08x",i,s));
       
   518 			StartHoldOffTimer();
       
   519 			break;
       
   520 		default:
       
   521 			__KTRACE_OPT(KPANIC,Kern::Printf("iEraseState=%d",iEraseState));
       
   522 			FLASH_FAULT();
       
   523 		}
       
   524 	StartPollTimer(KFlashEraseTimerPeriod,KFlashEraseTimerRetries);
       
   525 	}
       
   526 
       
   527 void DMediaDriverFlashTemplate::SuspendErase()
       
   528 	{
       
   529 	__ASSERT_ALWAYS(iEraseState==EErase || iEraseState==ESuspendPending,FLASH_FAULT());
       
   530 	volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
       
   531 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendErase %08x",pF));
       
   532 	*pF=KCmdEraseSuspend;
       
   533 	CHANGE_ERASE_STATE(ESuspending);
       
   534 	StartPollTimer(KFlashSuspendTimerPeriod,KFlashSuspendTimerRetries);
       
   535 	}
       
   536 
       
   537 void DMediaDriverFlashTemplate::StartPendingRW()
       
   538 	{
       
   539 	// start any pending read or write requests
       
   540 	if (iReadReq)
       
   541 		DoRead();
       
   542 	if (iWriteReq)
       
   543 		{
       
   544 		// can start the write now
       
   545 		iWriteState=EWriting;
       
   546 		WriteStep();
       
   547 		}
       
   548 	}
       
   549 
       
   550 void DMediaDriverFlashTemplate::DoFlashReady(TUint32 aStatus)
       
   551 	{
       
   552 	// could be write completion, erase completion or suspend completion
       
   553 	if (iWriteState==EWriting)
       
   554 		{
       
   555 		// write completion
       
   556 		__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:WriteComplete %08x",aStatus));
       
   557 		TUint32 err=aStatus & (KStsWriteError|KStsVppLow|KStsLocked);
       
   558 		if (err)
       
   559 			{
       
   560 			iWriteState=EWriteIdle;
       
   561 			Complete(EReqWrite,KErrGeneral);
       
   562 			if (iEraseState==ESuspended)
       
   563 				StartErase();
       
   564 			}
       
   565 		else
       
   566 			WriteStep();
       
   567 		return;
       
   568 		}
       
   569 
       
   570 	// put the FLASH back into read mode
       
   571 	volatile TFLASHWORD* pF=(volatile TFLASHWORD*)(iBase+iErasePos);
       
   572 	*pF=KCmdReadArray;
       
   573 
       
   574 	if (iEraseState==ESuspending)
       
   575 		{
       
   576 		// erase suspend completion
       
   577 		__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendComplete %08x",aStatus));
       
   578 
       
   579 		// accumulate errors during erase
       
   580 		iEraseError|=(aStatus & (KStsEraseError|KStsVppLow|KStsLocked));
       
   581 
       
   582 		if (aStatus & KStsSuspended)
       
   583 			{
       
   584 			// at least one of the two FLASH devices has suspended
       
   585 			CHANGE_ERASE_STATE(ESuspended);
       
   586 
       
   587 			// start any pending read or write requests
       
   588 			StartPendingRW();
       
   589 			return;					// in case erase has been resumed by DoRead()
       
   590 			}
       
   591 
       
   592 		// erase completed before we suspended it
       
   593 		CHANGE_ERASE_STATE(EErase);
       
   594 		}
       
   595 	if (iEraseState==EErase || iEraseState==EEraseNoSuspend)
       
   596 		{
       
   597 		// erase completion
       
   598 		__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:EraseComplete %08x",aStatus));
       
   599 		CancelHoldOffTimer();
       
   600 
       
   601 		// accumulate errors during erase
       
   602 		iEraseError|=(aStatus & (KStsEraseError|KStsVppLow|KStsLocked));
       
   603 
       
   604 		TFLASHWORD x = FLASH_ERASE_WORD_VALUE;
       
   605 
       
   606 		// if no device error, verify that erase was successful
       
   607 		if (!iEraseError)
       
   608 			{
       
   609 			volatile TFLASHWORD* p=pF;
       
   610 			volatile TFLASHWORD* pE=p + FLASH_BYTES_TO_WORDS(iEraseBlockSize);
       
   611 			while(p<pE)
       
   612 				x&=*p++;
       
   613 			}
       
   614 		else
       
   615 			{
       
   616 			}
       
   617 		if (x == FLASH_ERASE_WORD_VALUE)
       
   618 			{
       
   619 			// erase OK
       
   620 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:VerifyErase OK"));
       
   621 			CHANGE_ERASE_STATE(EEraseIdle);
       
   622 
       
   623 			// complete the erase request
       
   624 			TInt r=iEraseError?KErrGeneral:KErrNone;
       
   625 			Complete(EReqErase,r);
       
   626 
       
   627 			// start any pending read or write requests
       
   628 			StartPendingRW();
       
   629 			}
       
   630 		else
       
   631 			{
       
   632 			// erase failed, so retry
       
   633 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:VerifyErase BAD"));
       
   634 			StartErase();
       
   635 			}
       
   636 		}
       
   637 	}
       
   638 
       
   639 void DMediaDriverFlashTemplate::DoFlashTimeout()
       
   640 	{
       
   641 	// TO DO: (optional)
       
   642 	// Take appropriate action to handle a timeout.
       
   643 	FLASH_FAULT();	// // EXAMPLE ONLY:
       
   644 	}
       
   645 
       
   646 DMediaDriverFlash* DMediaDriverFlash::New(TInt aMediaId)
       
   647 	{
       
   648 	return new DMediaDriverFlashTemplate(aMediaId);
       
   649 	}
       
   650 
       
   651 void DMediaDriverFlashTemplate::Isr(TAny* aPtr)
       
   652 	{
       
   653 	DMediaDriverFlashTemplate& d=*(DMediaDriverFlashTemplate*)aPtr;
       
   654 
       
   655 	
       
   656 	// TO DO: (mandatory)
       
   657 	// Write to the timer hardware register(s) to
       
   658 	// clear the timer interrupt
       
   659 	//
       
   660 	
       
   661 	d.IPostEvents(EPollTimer);
       
   662 	}
       
   663 
       
   664 void DMediaDriverFlashTemplate::IPostEvents(TUint32 aEvents)
       
   665 	{
       
   666 	iEvents|=aEvents;
       
   667 	iEventDfc.Add();
       
   668 	}