emulator/emulatorbsp/specific/nanddev.cpp
changeset 0 cec860690d41
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emulator/emulatorbsp/specific/nanddev.cpp	Tue Feb 02 01:39:10 2010 +0200
@@ -0,0 +1,416 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+// D_MEDNAND.CPP
+// 
+//
+
+#define _MEDIA_DRIVER
+#include <nand_media.h>
+#include <emulator.h>
+#include <property.h>
+
+/********************************************
+ * Driver definitions
+ ********************************************/
+const TInt KSimulatedDeviceId = 0xEC73;
+const CHAR KNandFileName[] = "NANDDRV.BIN";
+
+//
+// Platform dependent media driver class
+//
+class DMediaDriverNandWin32 : public DMediaDriverNand
+	{
+public:
+	DMediaDriverNandWin32(TMediaDevice aDevice);
+
+	// replacing pure virtual - NAND device specific stuff
+	virtual TInt Initialise();
+	virtual TInt GetDeviceId(TUint8& aDeviceId, TUint8& aManufacturerId);
+	virtual TInt DeviceRead(const TUint aPageAddress, TAny* aBuf, const TUint aLength);
+	virtual TInt DeviceWrite(const TUint aPageAddress, TAny* aBuf, const TUint aLength);
+	virtual TInt DeviceErase(const TUint aBlockAddress);
+	virtual TInt DeviceClose();
+
+public:
+	HANDLE iFile;
+	HANDLE iMapping;
+	TUint8* iBase;
+	};
+
+LOCAL_C TInt MapLastError()
+//
+// Map an NT error to an Epoc/32 error.
+//
+	{
+	__PATH_NOT_YET_TESTED;
+	DWORD r=GetLastError();
+	TInt res;
+	switch (r)
+		{
+	    case ERROR_SHARING_VIOLATION : res=KErrAccessDenied; break;
+	    case ERROR_LOCK_VIOLATION : res=KErrLocked; break;
+	    case ERROR_FILE_NOT_FOUND: res=KErrNotFound; break;
+	    case ERROR_PATH_NOT_FOUND: res=KErrPathNotFound; break;
+	    case ERROR_ALREADY_EXISTS:
+	    case ERROR_FILE_EXISTS:
+            res=KErrAlreadyExists;
+		    break;
+	    case ERROR_NOT_READY: res=KErrNotReady; break;
+	    case ERROR_UNRECOGNIZED_VOLUME:
+	    case ERROR_NOT_DOS_DISK:
+		    res=KErrUnknown;
+		    break;
+	    case ERROR_UNRECOGNIZED_MEDIA: res=KErrCorrupt; break;
+	    case ERROR_INVALID_NAME: res=KErrBadName; break;
+	    case ERROR_NO_MORE_FILES: res=KErrEof; break;
+		case ERROR_DISK_FULL: res=KErrDiskFull; break;
+		default: res=KErrGeneral;
+		}
+	return(res);
+	}
+
+TInt DMediaDriverNandWin32::Initialise()
+//
+// Create the simulated NAND file if necessary and
+// map it into memory.
+//
+	{
+	__PATH_TESTED;
+
+	// locate/open the file that models the flash
+	CHAR filename[MAX_PATH];
+	strcpy(filename, Property::GetString("EmulatorMediaPath"));
+	if (!Emulator::CreateAllDirectories(filename))
+		{
+		__PATH_NOT_YET_TESTED;
+		return Emulator::LastError();
+		}
+	strcat(filename, KNandFileName);
+	iFile = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+
+	if (iFile == INVALID_HANDLE_VALUE)
+		{
+		__PATH_NOT_YET_TESTED;
+		return Emulator::LastError();
+		}
+
+	const TUint32 flashSizeInBytes = iNumBlocks * iNumPagesPerBlock * (iNumBytesMain + iNumBytesSpare);
+
+	SetFilePointer(iFile, flashSizeInBytes, NULL, FILE_BEGIN);
+	SetEndOfFile(iFile);
+	
+	iMapping = CreateFileMappingA(iFile, NULL, PAGE_READWRITE, 0, flashSizeInBytes, NULL);
+	if (iMapping == NULL)
+		{
+		__PATH_NOT_YET_TESTED;
+		return Emulator::LastError();
+		}
+
+	iBase = (TUint8*)MapViewOfFile(iMapping, FILE_MAP_WRITE, 0, 0, flashSizeInBytes);
+	if (iBase == NULL)
+		{
+		__PATH_NOT_YET_TESTED;
+		return Emulator::LastError();
+		}
+
+	return KErrNone;
+	}
+
+TInt DMediaDriverNandWin32::GetDeviceId(TUint8& aDeviceId, TUint8& aManufacturerId)
+	{
+	__PATH_TESTED;
+	
+	aManufacturerId = (KSimulatedDeviceId & 0xFF00) >> 8;
+	aDeviceId       = (KSimulatedDeviceId & 0xFF);
+	return KErrNone;
+	}
+
+TInt DMediaDriverNandWin32::DeviceRead(const TUint aPageAddress, TAny* aBuf, const TUint aLength)
+	{
+	__PATH_TESTED;
+
+	__NAND_ASSERT(aPageAddress < (iNumBlocks * iNumPagesPerBlock));
+	__NAND_ASSERT(   (aLength == iNumBytesMain)
+				  || (aLength == iNumBytesMain + iNumBytesSpare)
+				  || (aLength == iNumBytesSpare)				 );
+	
+#ifdef __TEST_MEDIA_DRIVER__
+		extern TBool gNoPower;
+		if(gNoPower)
+			return KErrBadPower;
+#endif
+
+	TUint8* readPoint;
+	if (aLength == iNumBytesMain)
+		{
+		__PATH_TESTED;
+		readPoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare));
+		}
+	else if (aLength == iNumBytesSpare)
+		{
+		__PATH_TESTED;
+		readPoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare)) + iNumBytesMain;
+		}
+	else if (aLength == (iNumBytesMain + iNumBytesSpare))
+		{
+		__PATH_TESTED;
+		readPoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare));
+		}
+	else
+		{
+		__PATH_NOT_YET_TESTED;
+		return KErrArgument;
+		}
+
+	for (TUint i = 0; i < aLength; i++)
+		{
+		((TUint8*)aBuf)[i] = readPoint[i];
+		}
+
+#ifdef __TEST_MEDIA_DRIVER__
+	extern TBool gECCFail;
+		if(gECCFail)
+		{
+			//introduce a random one bit error
+			TUint8* p=(TUint8*)aBuf;
+			TUint32 key=Kern::Random() % aLength;
+			TUint32 shift=1<<(Kern::Random() % 8);
+			p[key]=(TUint8)(p[key]&shift?p[key]-shift:p[key]+shift);
+			gECCFail=EFalse;
+		}
+#endif
+
+	return KErrNone;
+	}
+
+#ifdef __TEST_MEDIA_DRIVER__
+extern "C" TUint32 gbbm_get_sphy_blknum(TUint32, TUint32);
+#endif
+TInt DMediaDriverNandWin32::DeviceWrite(const TUint aPageAddress, TAny* aBuf, const TUint aLength)
+	{
+	__PATH_TESTED;
+
+	__NAND_ASSERT(aPageAddress < (iNumBlocks * iNumPagesPerBlock));
+	__NAND_ASSERT(   (aLength == iNumBytesMain)
+				  || (aLength == iNumBytesMain + iNumBytesSpare)
+				  || (aLength == iNumBytesSpare)				 );
+
+#ifdef __TEST_MEDIA_DRIVER__
+		extern TBool gNoPower;
+		extern TBool gPowerFail;
+		extern TUint32 gPowerFailAfter;
+		if(gNoPower)
+			return KErrBadPower;
+		if(gPowerFail)
+			{
+			if(gPowerFailAfter)
+				--gPowerFailAfter;
+			else
+				{
+				gPowerFail=EFalse;
+				gNoPower=ETrue;
+				extern TUint32 gNotificationType;
+				extern TUint32 KNandDbgNotifyPowerDown;
+				extern TInt NotifyThread();
+				if(gNotificationType==KNandDbgNotifyPowerDown)
+					NotifyThread();
+				return KErrBadPower;
+				}
+			}
+#endif
+	
+	TUint8* writePoint;
+	
+	if (aLength == iNumBytesMain)
+		{
+		__PATH_TESTED;
+		writePoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare));
+		}
+	else if (aLength == iNumBytesSpare)
+		{
+		__PATH_TESTED;
+		writePoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare)) + iNumBytesMain;
+		}
+	else if (aLength == (iNumBytesMain + iNumBytesSpare))
+		{
+		__PATH_TESTED;
+		writePoint = iBase + (aPageAddress * (iNumBytesMain + iNumBytesSpare));
+		}
+	else
+		{
+		__PATH_NOT_YET_TESTED;
+		return KErrArgument;
+		}
+	
+	for (TUint i = 0; i < aLength; i++)
+		{
+		writePoint[i] &= ((TUint8*)aBuf)[i];
+		}
+
+#ifdef __TEST_MEDIA_DRIVER__
+		extern TUint32 gFailAfter;
+		extern TUint32 gFailAfterCnt;
+		extern TBool gFailureType; //true-WriteFail, false-EraseFail
+		extern TBool gFailON;
+		if(gFailON && gFailureType)
+			{
+			if(gFailAfterCnt)
+				--gFailAfterCnt;
+			else
+				{
+				extern TUint32 FirstReadPUN;
+				extern DMediaDriverNand* gMediaDriverPtr;		
+				if(gbbm_get_sphy_blknum(0,aPageAddress/gMediaDriverPtr->iNumPagesPerBlock)==FirstReadPUN)
+					{
+					gFailAfterCnt=gFailAfter;
+					//notify failure
+					extern TUint32 gNotificationType;
+					extern TUint32 KNandDbgNotifyWriteFail;
+					extern TInt NotifyThread();
+					if(gNotificationType==KNandDbgNotifyWriteFail)
+						NotifyThread();
+
+					return KErrCorrupt;
+					}
+				}
+			}
+#endif
+
+	return KErrNone;
+	}
+
+TInt DMediaDriverNandWin32::DeviceErase(const TUint aBlockAddress)
+	{
+	__PATH_TESTED;
+	
+	__NAND_ASSERT(aBlockAddress < iNumBlocks);
+#ifdef __TEST_MEDIA_DRIVER__
+		extern TBool gNoPower;
+		extern TBool gPowerFail;
+		extern TUint32 gPowerFailAfter;
+		if(gNoPower)
+			return KErrBadPower;
+		if(gPowerFail)
+			{
+			if(gPowerFailAfter)
+				--gPowerFailAfter;
+			else
+				{
+				gPowerFail=EFalse;
+				gNoPower=ETrue;
+				extern TUint32 gNotificationType;
+				extern TUint32 KNandDbgNotifyPowerDown;
+				extern TInt NotifyThread();
+				if(gNotificationType==KNandDbgNotifyPowerDown)
+					NotifyThread();
+				return KErrBadPower;
+				}
+			}
+#endif
+	
+	const TUint bytesPerEraseBlock = iNumPagesPerBlock * (iNumBytesMain + iNumBytesSpare);
+	const TUint erasePos = aBlockAddress * bytesPerEraseBlock;
+	
+	TUint8* temp = iBase + erasePos;
+	for (TUint i=0; i < bytesPerEraseBlock; i++)
+		{
+		temp[i]=0xFF;
+		}
+	return KErrNone;
+	}
+
+TInt DMediaDriverNandWin32::DeviceClose()
+	{
+	__PATH_NOT_YET_TESTED;
+	TBool bRtn=UnmapViewOfFile(iBase);
+	if(!bRtn)
+		{
+		__PATH_NOT_YET_TESTED;
+		return(MapLastError());
+		}
+
+	bRtn=CloseHandle(iMapping);
+	if (!bRtn)
+		{
+		__PATH_NOT_YET_TESTED;
+		return(MapLastError());
+		}
+
+	bRtn=CloseHandle(iFile);
+	if (!bRtn)
+		{
+		__PATH_NOT_YET_TESTED;
+		return(MapLastError());
+		}
+
+	return KErrNone;
+	}
+
+DMediaDriverNandWin32::DMediaDriverNandWin32(TMediaDevice aDevice)
+	:	DMediaDriverNand(aDevice)
+	{
+	__PATH_TESTED;
+	}
+
+DMediaDriverNand* DMediaDriverNand::New(TMediaDevice aDevice)
+	{
+	__PATH_TESTED;
+	return new DMediaDriverNandWin32(aDevice);
+	}
+
+#ifdef __USE_CUSTOM_ALLOCATOR
+/**	
+	Concrete implementation of the NAND buffer allocator class
+		- Uses Kern::Alloc based allocation
+
+	@internalTechnology
+ */
+class TNandAllocatorWins : public TNandAllocatorBase
+	{
+public:
+	virtual TInt AllocateBuffers(SBufferInfo& aBufferInfo);	// Initialise the allocator
+	};
+
+/**	Concrete implementation of the NAND buffer allocator class
+	Creates a customallocator (using Kern::Alloc)
+
+	@param aBufferInfo A reference to a SBufferInfo containing the details of the PSL allocated buffer
+	@return Standard Symbian OS error code
+	@see TNandAllocatorBase::SCellInfo
+ */
+TInt TNandAllocatorWins::AllocateBuffers(SBufferInfo& aBufferInfo)
+	{
+	const TUint32 KNumBuffers		= 4;
+	const TUint32 KMaxNumBytesSpare = 16;
+	const TUint32 KMaxNumBytesMain	= 512;
+	const TUint32 KMaxNumBytesPage	= KMaxNumBytesSpare + KMaxNumBytesMain;
+
+	aBufferInfo.iBytesPerSpareArray = KMaxNumBytesSpare;
+	aBufferInfo.iBytesPerMainArray = KMaxNumBytesMain;
+	aBufferInfo.iBufferCount = KNumBuffers;
+
+	aBufferInfo.iBufferP = reinterpret_cast<TUint8*>(Kern::Alloc(KMaxNumBytesPage * KNumBuffers));
+
+	return(aBufferInfo.iBufferP ? KErrNone : KErrNoMemory);
+	}
+
+/**
+Create an allocator suitable for use on this target
+@internalComponent
+*/
+TNandAllocatorBase* DMediaDriverNand::ExtensionInitAllocator()
+	{
+	return new TNandAllocatorWins;
+	}
+#endif