os/boardsupport/emulator/emulatorbsp/specific/lffsdev.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // wins\specific\lffsdev.cpp
    15 // 
    16 //
    17 
    18 #include <flash_media.h>
    19 #include <emulator.h>
    20 #include <property.h>
    21 
    22 #define FLASH_FAULT()	Kern::Fault("LFFSDEV",__LINE__)
    23 
    24 //#define M18_EMULATION // Test for Control Mode operation
    25 
    26 /********************************************
    27  * Driver definitions
    28  ********************************************/
    29 
    30 /** LFFS image name */
    31 const CHAR KLfsFileName[] = "LFSLDRV.BIN";
    32 
    33 
    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
    41 
    42 //-- other possible LFFS related entries in "epoc.ini" file:
    43 //-- "FlashHoldOffTime"   default value = iEraseTime/10
    44 
    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
    48 
    49 
    50 /** 
    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). 
    53 */
    54 
    55 struct TLfsParams
    56 	{
    57 	TInt iEraseSize;
    58 	};
    59 
    60 #ifdef _DEBUG
    61 /***************************************************
    62  * ControlIO command types - for debug builds, only
    63  ***************************************************/
    64 
    65 enum TCtrlIoTypes
    66 	{
    67 	//KCtrlIoRww=0,
    68 	KCtrlIoTimeout=1
    69 	};
    70 #endif
    71 
    72 
    73 const TInt KDataBufSize=1024;
    74 
    75 /********************************************
    76  * Media driver class
    77  ********************************************/
    78 class DMediaDriverFlashWin32 : public DMediaDriverFlash
    79 	{
    80 public:
    81 	enum TState
    82 		{
    83 		EIdle=0,
    84 		EWriting=1,
    85 		EEraseNoSuspend=2,
    86 		EErase=3,
    87 		ESuspendPending=4,
    88 		ESuspending=5,
    89 		ESuspended=6,
    90 		EErasePending=7
    91 		};
    92 public:
    93 	DMediaDriverFlashWin32(TInt aMediaId);
    94 public:
    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);
   103 public:
   104 	void HandleEvent();
   105 	void StartTimer(TInt aMicros);
   106 	void StartErase();
   107 	void SuspendErase();
   108 	void CompleteErase();
   109 	void CompleteWrite();
   110 	void CompleteSuspend();
   111 	void StartPendingRW();
   112 	void ReadFlashParameters();
   113 public:
   114 	static void TimerFn(TAny* aPtr);
   115 	static void EventDfc(TAny* aPtr);
   116 #ifdef _DEBUG
   117 public:
   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);
   121 #endif
   122 public:
   123 	TState iState;
   124 	
   125 	TInt iSize;
   126 	TInt iEraseBlockSize;
   127 	TInt iEraseTime;
   128 	TInt iSuspendHoldOffTime;
   129 	TInt iResumeTime;
   130 	TInt iWriteBlockSize;
   131 	TInt iWriteTime;
   132     
   133 	HANDLE iFile;
   134 	HANDLE iMapping;
   135 	TUint8* iBase;
   136 	TUint8* iData;		// data being written
   137 	
   138 	NTimer iTimer;
   139 	TDfc iEventDfc;
   140 	TUint32 iTickPeriod;
   141 	TUint32 iEraseCounter;
   142 	TUint32 iErasePos;
   143 	TInt iTimerExtra;
   144 
   145 #ifdef _DEBUG
   146 public:
   147     TUint8 iCtrlIoState;
   148 #endif
   149 	};
   150 
   151 DMediaDriverFlashWin32::DMediaDriverFlashWin32(TInt aMediaId)
   152 	:	DMediaDriverFlash(aMediaId),
   153 		iTimer(&TimerFn,this),
   154 		iEventDfc(&EventDfc,this,NULL,2),
   155 		iTickPeriod(NKern::TickPeriod())
   156 	{
   157 	// iState=EIdle;
   158 #ifdef _DEBUG
   159     //iCtrlIoState=EIdle;
   160 #endif
   161 
   162 	}
   163 
   164 void DMediaDriverFlashWin32::ReadFlashParameters()
   165 //
   166 // Read the flash parameters from the ini file, or use defaults
   167 //
   168 	{
   169    
   170 	iSize = Property::GetInt("FlashSize", KDefaultFlashSize);
   171 
   172 	TInt nblocks = Property::GetInt("FlashEraseBlocks", 0);
   173 	if (nblocks == 0)
   174 		nblocks = iSize/Property::GetInt("FlashEraseSize", KEraseBlockSize);
   175 
   176 	iEraseBlockSize = iSize / nblocks;
   177 	__ASSERT_ALWAYS(iEraseBlockSize * nblocks == iSize, FLASH_FAULT());
   178 	__ASSERT_ALWAYS((iEraseBlockSize & (iEraseBlockSize-1)) == 0, FLASH_FAULT());
   179 
   180 	iEraseTime = Property::GetInt("FlashEraseTime", KFlashEraseTime);
   181 	
   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());
   186 
   187 	iWriteTime = Property::GetInt("FlashWriteTime", KFlashWriteTime);
   188 	
   189 	}
   190 
   191 TInt DMediaDriverFlashWin32::Initialise()
   192 	{
   193 	iEventDfc.SetDfcQ(iPrimaryMedia->iDfcQ);
   194 	iData=(TUint8*)Kern::Alloc(KDataBufSize);
   195 	if (!iData)
   196 		return KErrNoMemory;
   197 
   198 	ReadFlashParameters();
   199 
   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);
   206 	
   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();
   210 
   211 	TLfsParams p;
   212 	p.iEraseSize = -1;
   213 	DWORD bytes;
   214 	TBool valid;
   215 	
   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)
   220 	{
   221         valid = ETrue; //-- read it OK.
   222 	}
   223 	else
   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.
   227 
   228 		const TInt forceImgMount = Property::GetInt("FlashForceImgMount", 0);
   229         if(!forceImgMount)
   230 		{
   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();
   236 		    
   237 		valid = EFalse;
   238 		}
   239         else
   240         {//-- mount LFFS image forcingly.
   241             valid = ETrue;
   242         }
   243 	}
   244 
   245 	iMapping = CreateFileMappingA(iFile, NULL, PAGE_READWRITE, 0, iSize, NULL);
   246 	if (iMapping == NULL)
   247 		return Emulator::LastError();
   248 
   249 	iBase = (TUint8*)MapViewOfFile(iMapping, FILE_MAP_WRITE, 0, 0, iSize);
   250 	if (iBase == NULL)
   251 		return Emulator::LastError();
   252 
   253 	//-- zero-fill media image it doesn't contain TLfsParams data at the very end.
   254 	if (!valid)
   255 	    {
   256 		memclr(iBase, iSize);
   257         }
   258 
   259 	return KErrNone;
   260 	}
   261 
   262 TUint32 DMediaDriverFlashWin32::EraseBlockSize()
   263 	{
   264 	return iEraseBlockSize;
   265 	}
   266 
   267 TUint32 DMediaDriverFlashWin32::TotalSize()
   268 	{
   269 	return iSize;
   270 	}
   271 
   272 TInt DMediaDriverFlashWin32::DoRead()
   273 	{
   274 	if (iWriteReq)
   275 		return 1;	// write in progress so defer read
   276 	
   277 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:DoRead"));
   278 
   279 	if (iState==EErasePending)
   280 		{
   281 		iTimer.Cancel();
   282 		iState = ESuspended;
   283 		}
   284 	if (iState==EIdle || iState==ESuspended)
   285 		{
   286 		// can do the read now
   287 		TInt pos=(TInt)iReadReq->Pos();
   288 		TInt len=(TInt)iReadReq->Length();
   289 
   290 		TPtrC8 des(iBase+pos,len);
   291 		TInt r=iReadReq->WriteRemote(&des,0);
   292 		Complete(EReqRead,r);
   293 		if (iState==ESuspended)
   294 			StartErase();
   295 		}
   296 	else if (iState==EErase)
   297 		{
   298 		// erase in progress - suspend it
   299 		SuspendErase();
   300 		}
   301 	else if (iState==EEraseNoSuspend)
   302 		iState=ESuspendPending;
   303 	// wait for suspend to complete
   304 	return KErrNone;
   305 	}
   306 
   307 TInt DMediaDriverFlashWin32::DoWrite()
   308 	{
   309 	if (iReadReq)
   310 		return 1;	// read in progress so defer write
   311 
   312 	if (iState==EErasePending)
   313 		{
   314 		iTimer.Cancel();
   315 		iState = ESuspended;
   316 		}
   317 	if (iState==EIdle || iState==ESuspended)
   318 		{
   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()));
   322 		if (iState==EIdle)
   323 			iState=EWriting;
   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);
   329 		}
   330 	else if (iState==EErase)
   331 		{
   332 		// erase in progress - suspend it
   333 		SuspendErase();
   334 		}
   335 	else if (iState==EEraseNoSuspend)
   336 		iState=ESuspendPending;
   337 	// wait for suspend to complete
   338 	return KErrNone;
   339 	}
   340 
   341 void DMediaDriverFlashWin32::CompleteWrite()
   342 //
   343 // Do the actual write in the completion
   344 // Transfer data in blocks from the client and AND it to the 'flash'
   345 //
   346 	{
   347 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:WriteComplete"));
   348 
   349 	TInt r = KErrNone;
   350 	TUint8* flash = iBase + (TInt)iWriteReq->Pos();
   351 	TInt len = (TInt)iWriteReq->Length();
   352 	TInt offset = 0;
   353 	while (len > 0)
   354 		{
   355 		TInt size = Min(len, KDataBufSize);
   356 		TPtr8 des(iData,size);
   357 		r = iWriteReq->ReadRemote(&des, offset);
   358 		if (r!=KErrNone)
   359 			break;
   360 		len -= size;
   361 		offset += size;
   362 		const TUint8* ptr = iData;
   363 		do
   364 			{
   365 			*flash++ &= *ptr++;
   366 			} while (--size > 0);
   367 		}
   368 
   369 	if (iState == EWriting)
   370 		iState = EIdle;
   371 	Complete(EReqWrite,r);
   372 	if (iState == ESuspended)
   373 		StartErase();
   374 	}
   375 
   376 TInt DMediaDriverFlashWin32::DoErase()
   377 	{
   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());
   388 	iErasePos=pos;
   389 	StartErase();
   390 	return KErrNone;
   391 	}
   392 
   393 void DMediaDriverFlashWin32::StartTimer(TInt aMicros)
   394 	{
   395 	aMicros += iTimerExtra - (iTickPeriod>>1);
   396 	if (aMicros < 0)
   397 		{
   398 		iTimerExtra = aMicros + (iTickPeriod>>1);
   399 		iEventDfc.Enque();		// go off 'immediately'
   400 		}
   401 	else
   402 		{
   403 		iTimerExtra = 0;
   404 		iTimer.OneShot(aMicros / iTickPeriod);
   405 		}
   406 	}
   407 
   408 void DMediaDriverFlashWin32::TimerFn(TAny* aPtr)
   409 	{
   410 	((DMediaDriverFlashWin32*)aPtr)->iEventDfc.Add();
   411 	}
   412 
   413 void DMediaDriverFlashWin32::EventDfc(TAny* aPtr)
   414 	{
   415 	((DMediaDriverFlashWin32*)aPtr)->HandleEvent();
   416 	}
   417 
   418 void DMediaDriverFlashWin32::HandleEvent()
   419 	{
   420 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:Event %d", iState));
   421 	switch (iState)
   422 		{
   423 	case ESuspended:
   424 	case EWriting:	// write completed
   425 		{
   426 #ifdef _DEBUG
   427 		if(iCtrlIoState==ECtrlIoTimeOutPrep)
   428 			{
   429 			iState=EIdle;
   430 			iCtrlIoState=EIdle;
   431 			Complete(EReqWrite,KErrNotReady);
   432 			}
   433 		else
   434 #endif
   435 			CompleteWrite();
   436 		break;
   437 		}
   438 	case EEraseNoSuspend:
   439 		{
   440 #ifdef _DEBUG
   441 		if(iCtrlIoState==ECtrlIoTimeOutPrep)
   442 			{
   443 			iState=EIdle;
   444 			iCtrlIoState=EIdle;
   445 			Complete(EReqErase,KErrNotReady);
   446 			}
   447 		else
   448 			{
   449 #endif
   450 		TInt remain = iEraseCounter - NKern::TickCount();
   451 		if (remain <= 0)
   452 			CompleteErase();
   453 		else
   454 			{
   455 			iState=EErase;
   456 			StartTimer(remain * iTickPeriod);
   457 			}
   458 #ifdef _DEBUG
   459 			}
   460 #endif
   461 		break;
   462 		}
   463 	case EErasePending:
   464 		StartErase();
   465 		break;
   466 	case EErase:	// erase completed
   467 		CompleteErase();
   468 		break;
   469 	case ESuspendPending:
   470 		if (TInt(iEraseCounter - NKern::TickCount()) <= 0)
   471 			CompleteErase();
   472 		else
   473 			SuspendErase();
   474 		break;
   475 	case ESuspending:
   476 		CompleteSuspend();
   477 		break;
   478 	default:
   479 		__KTRACE_OPT(KPANIC,Kern::Printf("iState=%d",iState));
   480 		FLASH_FAULT();
   481 		}
   482 	}
   483 
   484 void DMediaDriverFlashWin32::StartErase()
   485 //
   486 // Continue an erase - iEraseCounter has the remaining time for the erase
   487 //
   488 	{
   489 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:StartErase %08x",iBase+iErasePos));
   490 	switch (iState)
   491 		{
   492 	case ESuspended:
   493 		iState = EErasePending;
   494 		StartTimer(iResumeTime);
   495 		break;
   496 	case EIdle:	// starting to erase
   497 		iEraseCounter = iEraseTime;
   498 	case EErasePending:
   499 		{
   500 		iState = EEraseNoSuspend;
   501 		TUint32 remain = iEraseCounter;
   502 		iEraseCounter = NKern::TickCount() + remain/iTickPeriod;
   503 		StartTimer(Min(remain, iSuspendHoldOffTime));
   504 		}
   505 		break;
   506 	default:
   507 		__KTRACE_OPT(KPANIC,Kern::Printf("iState=%d",iState));
   508 		FLASH_FAULT();
   509 		}
   510 	}
   511 
   512 void DMediaDriverFlashWin32::SuspendErase()
   513 	{
   514 	__ASSERT_ALWAYS(iState==EErase || iState==ESuspendPending,FLASH_FAULT());
   515 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendErase %08x",iBase+iErasePos));
   516 	iTimer.Cancel();
   517 	TInt remain = Max(0, TInt(iEraseCounter - NKern::TickCount()));
   518 	iEraseCounter = remain * iTickPeriod;
   519 	iState = ESuspending;
   520 	StartTimer(0);
   521 	}
   522 
   523 void DMediaDriverFlashWin32::CompleteSuspend()
   524 	{
   525 	// erase suspend completion
   526 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:SuspendComplete"));
   527 
   528 	iState = ESuspended;
   529 	// start any pending read or write requests
   530 	StartPendingRW();
   531 	}
   532 
   533 void DMediaDriverFlashWin32::CompleteErase()
   534 //
   535 // Do the actual erase in the completion
   536 //
   537 	{
   538 	// erase completion
   539 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash:EraseComplete"));
   540 
   541 	memset(iBase + iErasePos, 0xff, iEraseBlockSize);
   542 
   543 	// complete the erase request
   544 	iState = EIdle;
   545 	Complete(EReqErase,KErrNone);
   546 
   547 	// start any pending read or write requests
   548 	StartPendingRW();
   549 	}
   550 
   551 
   552 void DMediaDriverFlashWin32::StartPendingRW()
   553 	{
   554 	// start any pending read or write requests
   555 	if (iReadReq)
   556 		DoRead();
   557 	if (iWriteReq)
   558 		DoWrite();
   559 	}
   560 
   561 #ifdef _DEBUG
   562 // Override the base class version in order to provide access to ControlIO
   563 //
   564 TInt DMediaDriverFlashWin32::Request(TLocDrvRequest& m)
   565 	{
   566 	TInt r;
   567 	TInt id=m.Id();
   568 	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DMediaDriverFlashWin32::Request %d",id));
   569 	if (id!=DLocalDrive::EControlIO)
   570 		{
   571 		r=DMediaDriverFlash::Request(m);
   572 		return r;
   573 		}
   574 	r=ControlIO((TInt)m.iArg[0],m.iArg[1],m.iArg[2]);
   575 	DMediaDriver::Complete(m,r);
   576 	return r;
   577 	}
   578 
   579 TInt DMediaDriverFlashWin32::ControlIO(TInt aCommand,TAny* /*aParam1*/,TAny* /*aParam2*/)
   580 	{
   581 	switch (aCommand)
   582 		{
   583 		case(KCtrlIoTimeout):
   584 			{
   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)
   589 				{
   590 				__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash: ControlIO request before previous completed"));
   591 				return KErrServerBusy;
   592 				}
   593 			else
   594 				{
   595 				__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash: ControlIO timeout initiated"));
   596 				iCtrlIoState=ECtrlIoTimeOutPrep;
   597 				}
   598 			break;
   599 			}
   600 		
   601 		default:
   602 			{
   603 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Flash: ERROR - unrecognised ControlIO command %d",aCommand));
   604 			FLASH_FAULT();
   605 			break;
   606 			}
   607 		}
   608 	return KErrNone;
   609 	}
   610 	
   611 #endif
   612 
   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 
   620 // fault.
   621 	{
   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) );
   631 #endif
   632 	return KErrCompletion;	// synchronous completion
   633 	}
   634 
   635 DMediaDriverFlash* DMediaDriverFlash::New(TInt aDevice)
   636 	{
   637 	return new DMediaDriverFlashWin32(aDevice);
   638 	}
   639 
   640 
   641 
   642