omap3530/beagle_drivers/medwb/medwb.cpp
changeset 23 117faf51deac
child 33 2905910218db
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/beagle_drivers/medwb/medwb.cpp	Wed Mar 03 13:10:32 2010 +0000
@@ -0,0 +1,1149 @@
+/* Cypress West Bridge API source file 
+## ===========================
+##
+##  Copyright Cypress Semiconductor Corporation, 2006-2009,
+##  All Rights Reserved
+##  UNPUBLISHED, LICENSED SOFTWARE.
+##
+##  CONFIDENTIAL AND PROPRIETARY INFORMATION
+##  WHICH IS THE PROPERTY OF CYPRESS.
+##
+##  Use of this file is governed
+##  by the license agreement included in the file
+##
+##     <install>/license/license.txt
+##
+##  where <install> is the Cypress software
+##  installation root directory path.
+##
+## ===========================
+*/
+
+#include "locmedia.h"
+#include "platform.h"
+//#include "variantmediadef.h"
+#include <assp\omap3530_assp\CyAsSymbianStorageDriver.h>
+
+//#define REGIST_MEDIA_USE_MMC
+#define _MEDWB_DEBUG_1_
+//#define _MEDWB_DEBUG_2_
+
+//#define INTERVAL_FOR_WB 15 // 15 -- OK
+#define WB_BUFFER_SIZE	2*(65536 + 512)
+#define WB_RETRY_COUNT 2
+
+//const TInt KStackNumber = 0;
+const TInt KDiskSectorSize=512;
+const TInt KDiskSectorShift=9;
+//const TInt KIdleCurrentInMilliAmps = 1;
+
+const TInt KMBRFirstPartitionEntry=0x1BE;
+
+TUint8	ptrWBBuffer[WB_BUFFER_SIZE];
+
+
+template <class T>
+inline T UMin(T aLeft,T aRight)
+	{return(aLeft<aRight ? aLeft : aRight);}
+
+
+class DPhysicalDeviceMediaWB : public DPhysicalDevice
+	{
+public:
+	DPhysicalDeviceMediaWB();
+
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DBase*& aChannel, TInt aMediaId, const TDesC8* aInfo, const TVersion& aVer);
+	virtual TInt Validate(TInt aDeviceType, const TDesC8* aInfo, const TVersion& aVer);
+	virtual TInt Info(TInt aFunction, TAny* a1);
+	};
+
+
+class DMediaDriverWB : public DMediaDriver
+	{
+public:
+	DMediaDriverWB(TInt aMediaId);
+	~DMediaDriverWB();
+	// ...from DMediaDriver
+	virtual void Close();
+	// replacing pure virtual
+	virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage*);
+	virtual TInt Request(TLocDrvRequest& aRequest);
+	virtual TInt PartitionInfo(TPartitionInfo& anInfo);
+	virtual void NotifyPowerDown();
+	virtual void NotifyEmergencyPowerDown();
+	// For creation by DPhysicalDeviceMediaMmcFlash
+	TInt DoCreate(TInt aMediaId);
+
+private:
+
+private:
+	// MMC device specific stuff
+	TInt DoRead(TLocDrvRequest&);
+	TInt DoWrite(TLocDrvRequest&);
+	TInt DoFormat(TLocDrvRequest&);
+	TInt Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo);
+
+
+	TInt DecodePartitionInfo();
+	TInt WritePartitionInfo();
+	TInt GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry);
+	TInt CreateDefaultPartition();
+
+
+
+	static void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors);
+
+	TInt CheckDevice(int aReqType);
+	
+	void Reset();
+
+private:
+	TInt iMediaId;
+	TPartitionInfo* iPartitionInfo;
+	TBool iMbrMissing;
+	TUint iHiddenSectors;						// bootup / password
+
+	TUint8* ptrWriteBuf;							// start of current buffer region
+	TUint8* ptrReadBuf;							// start of current buffer region
+	TInt	read_size;
+	TInt	read_pos;
+
+	TInt 	iUnitSize;
+	TInt	iBlockSize;
+	};
+	
+// ======== DPhysicalDeviceMediaMmcFlash ========
+
+
+DPhysicalDeviceMediaWB::DPhysicalDeviceMediaWB()
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("=mmd:ctr");
+	#endif
+	iUnitsMask = 0x01;
+	iVersion = TVersion(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
+	}
+
+
+TInt DPhysicalDeviceMediaWB::Install()
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("=mmd:ins");
+	#endif
+	_LIT(KDrvNm, "Media.WB");
+	return SetName(&KDrvNm);
+	}
+
+
+void DPhysicalDeviceMediaWB::GetCaps(TDes8& /* aDes */) const
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("=mmd:cap");
+	#endif
+	}
+								 
+									 
+TInt DPhysicalDeviceMediaWB::Info(TInt aFunction, TAny* /*a1*/)
+//
+// Return the priority of this media driver
+//
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("=mmd:info");
+	#endif
+	if (aFunction==EPriority)
+		return KMediaDriverPriorityNormal;
+	// Don't close media driver when peripheral bus powers down. This avoids the need for Caps() to power up the stack.
+	if (aFunction==EMediaDriverPersistent)
+		return KErrNone;
+	return KErrNotSupported;
+	}
+								 
+TInt DPhysicalDeviceMediaWB::Validate(TInt aDeviceType, const TDesC8* /*aInfo*/, const TVersion& aVer)
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("=mmd:validate aDeviceType %d\n", aDeviceType);
+	#endif
+	if (!Kern::QueryVersionSupported(iVersion,aVer))
+	{	
+	#ifdef _MEDWB_DEBUG_3_
+		Kern::Printf("Validate -> KErrNotSupported\n");
+	#endif
+		return KErrNotSupported;
+	}
+	if (aDeviceType!=MEDIA_DEVICE_MMC)
+	{
+	#ifdef _MEDWB_DEBUG_3_
+		Kern::Printf("Validate -> Wrong DeviceType\n");
+	#endif
+		return KErrNotSupported;
+	}
+	return KErrNone;
+	}
+	
+								 
+TInt DPhysicalDeviceMediaWB::Create(DBase*& aChannel, TInt aMediaId, const TDesC8* /*aInfo*/, const TVersion& aVer)
+//
+// Create an MMC Card media driver.
+//
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("=mmd:crt");
+	#endif
+	if (!Kern::QueryVersionSupported(iVersion,aVer))
+		return KErrNotSupported;
+
+	DMediaDriverWB* pD = new DMediaDriverWB(aMediaId);
+	aChannel=pD;
+
+	TInt r=KErrNoMemory;
+	if (pD)
+		r=pD->DoCreate(aMediaId);
+
+	#ifdef REGIST_MEDIA_USE_MMC
+	if (r==KErrNone)
+		pD->OpenMediaDriverComplete(KErrNone);
+	#endif
+	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:mdf"));
+	return r;
+	}
+
+
+
+// Helper
+template <class T>
+inline T* KernAlloc(const TUint32 n)
+	{ return static_cast<T*>(Kern::Alloc(n * sizeof(T))); }
+
+// ---- ctor, open, close, dtor ----
+
+#pragma warning( disable : 4355 )	// this used in initializer list
+DMediaDriverWB::DMediaDriverWB(TInt aMediaId)
+   :DMediaDriver(aMediaId),
+	iMediaId(iPrimaryMedia->iNextMediaId)
+	{
+	#ifdef _MEDWB_DEBUG_2_
+	Kern::Printf("=mmd:wb");
+	// NB aMedia Id = the media ID of the primary media, iMediaId = the media ID of this media
+	Kern::Printf("DMediaDriverWB(), iMediaId %d, aMediaId %d\n", iMediaId, aMediaId);
+	#endif
+	}
+
+#pragma warning( default : 4355 )
+TInt DMediaDriverWB::DoCreate(TInt /*aMediaId*/)
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf(">mmd:opn");
+	#endif
+	iUnitSize = CyAsSymbianStorageDriver::GetUnitSize();
+	iBlockSize = CyAsSymbianStorageDriver::GetBlockSize();
+	if( iBlockSize == 0 )
+		iBlockSize = 1;
+	
+	read_pos = 0x7FFFFFFF;
+	read_size = 0;
+
+	// get card characteristics
+	SetTotalSizeInBytes(CyAsSymbianStorageDriver::GetMediaSize());
+	
+	// get buffer memory from EPBUS
+	ptrReadBuf = ptrWBBuffer;
+	ptrWriteBuf = &ptrWBBuffer[65536+512];
+	
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("<mmd:opn");
+	#endif
+	return(KErrNone);
+	}
+
+void DMediaDriverWB::Close()
+//
+// Close the media driver - also called on media change
+//
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("=mmd:cls");
+	#endif
+	EndInCritical();
+	//CompleteRequest(KErrNotReady);
+	DMediaDriver::Close();
+	}
+
+
+DMediaDriverWB::~DMediaDriverWB()
+	{
+
+	}
+
+
+// ---- media access ----
+
+TInt DMediaDriverWB::DoRead(TLocDrvRequest& iCurrentReq)
+//
+// set up iReqStart, iReqEnd and iReqCur and launch first read.  Subsequent reads
+// will be launched from the callback DFC.
+//
+	{
+	Int64 pos=iCurrentReq.Pos();
+	Int64 length=iCurrentReq.Length();
+	TInt r;
+	if (length<0 || pos<0 || (pos+length)>KMaxTInt)
+		return KErrGeneral;
+	TInt p=(TInt)pos;
+	TInt l=(TInt)length;
+	
+	if (p+l>CyAsSymbianStorageDriver::GetMediaSize())
+		return KErrGeneral;
+
+	TInt pos_block = p / iBlockSize;
+	TInt pos_offset =  p % iBlockSize;
+	TInt size_block = l / iBlockSize; 
+	TInt size_offset = l % iBlockSize; 
+	
+	TUint buf_offset = 0;
+	TInt	local_pos;
+
+	#ifdef _MEDWB_DEBUG_2_
+	Kern::Printf("WB::Read> real (%d@%d)", l, p);
+	Kern::Printf("WB::Read> pos_block - %d", pos_block) ;
+	Kern::Printf("WB::Read> pos_offset - %d", pos_offset) ;
+	Kern::Printf("WB::Read> size_block - %d", size_block) ;
+	Kern::Printf("WB::Read> size_offset - %d", size_offset) ;
+	#endif
+
+	#ifdef INTERVAL_FOR_WB
+	NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	if( pos_block == read_pos )
+	{
+		if( read_size < l )
+		{
+			buf_offset = read_size;
+			size_block = (l-read_size) / iBlockSize;
+			size_offset = (l-read_size) % iBlockSize;
+
+			local_pos = pos_block + (read_size /iBlockSize);
+		}
+		else
+		{
+			TPtrC8 des((ptrReadBuf+pos_offset), l);
+				
+			r = iCurrentReq.WriteRemote(&des, 0);
+			
+			return r;
+		}
+	}
+	#if 0
+	else if( (read_pos + (read_size/iBlockSize)) > pos_block )
+	{
+		TInt adjust_offset;
+		TInt adjust_size;
+		adjust_offset = (read_pos - pos_block) * iBlockSize;
+		adjust_size = read_size - adjust_offset;
+		
+		memcpy(ptrReadBuf, &ptrReadBuf[adjust_offset], adjust_size );
+
+		read_pos = pos_block;
+		read_size = adjust_size;
+	
+		if( read_size < l )
+		{
+			buf_offset = read_size;
+			size_block = (l-read_size) / iBlockSize;
+			size_offset = (l-read_size) % iBlockSize;
+
+			local_pos = pos_block + (read_size /iBlockSize);
+		}
+		else
+		{
+			TPtrC8 des((ptrReadBuf+pos_offset), l);
+				
+			r = iCurrentReq.WriteRemote(&des, 0);
+			
+			return r;
+		}
+	}
+	#endif
+	else
+		local_pos = read_pos = pos_block;
+		
+	#ifdef _MEDWB_DEBUG_2_
+	Kern::Printf("WB::Read> local_pos - %d", local_pos) ;
+	Kern::Printf("WB::Read> buf_offset - %d", buf_offset) ;
+	#endif
+
+
+	if( size_block )
+	{
+		CyAsSymbianStorageDriver::Read(local_pos, size_block, (void *)(ptrReadBuf+buf_offset));
+		local_pos += size_block;
+		buf_offset += (size_block*iBlockSize);
+	#ifdef INTERVAL_FOR_WB
+		NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	}
+	
+	if( pos_offset || size_offset )
+	{
+		CyAsSymbianStorageDriver::Read(local_pos, 1, (void *)(ptrReadBuf+buf_offset) );
+		local_pos += size_block;
+		buf_offset += iBlockSize;
+	#ifdef INTERVAL_FOR_WB
+		NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	}
+
+	read_size = buf_offset;
+		
+	TPtrC8 des((ptrReadBuf+pos_offset), l);
+		
+	r = iCurrentReq.WriteRemote(&des, 0);
+	
+	return r;
+	}
+
+
+TInt DMediaDriverWB::DoWrite(TLocDrvRequest& iCurrentReq)
+//
+// set up iReqStart, iReqEnd, and iReqCur, and launch first write.  Any subsequent
+// writes are launched from the session end DFC.  LaunchWrite() handles pre-reading
+// any sectors that are only partially modified.
+//
+	{
+	Int64 pos = iCurrentReq.Pos();
+	Int64 length = iCurrentReq.Length();
+	TInt r;
+	if (length<0 || pos<0 || (pos+length)>KMaxTInt)
+		return KErrGeneral;
+	TInt p=(TInt)pos;
+	TInt l=(TInt)length;
+
+	if (p+l>CyAsSymbianStorageDriver::GetMediaSize())
+		return KErrGeneral;
+
+	#ifdef _MEDWB_DEBUG_2_
+	Kern::Printf("WB::Write> (%d@%d)", l, p);
+	#endif
+	#ifdef INTERVAL_FOR_WB
+	NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	
+	TInt pos_block = p / iBlockSize;
+	TInt pos_offset =  p % iBlockSize;
+	TInt size_block = l / iBlockSize; 
+	TInt size_offset = l % iBlockSize; 
+	
+	TUint buf_offset = 0;
+	TInt	local_pos;
+	TInt	w_block_size = 0;
+
+	local_pos = pos_block;
+	
+	if( size_block )
+	{
+		CyAsSymbianStorageDriver::Read(local_pos, size_block, (void *)(ptrWriteBuf+buf_offset));
+		local_pos += size_block;
+		buf_offset += (size_block*iBlockSize);
+		w_block_size += size_block;
+	#ifdef INTERVAL_FOR_WB
+		NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	}
+	
+	if( pos_offset || size_offset )
+	{
+		CyAsSymbianStorageDriver::Read(local_pos, 1, (void *)(ptrWriteBuf+buf_offset) );
+		local_pos += size_block;
+		buf_offset += iBlockSize;
+		w_block_size ++;
+	#ifdef INTERVAL_FOR_WB
+		NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	}
+	
+	#ifdef _MEDWB_DEBUG_2_
+	Kern::Printf("WB::Write> pos_block - %d", pos_block) ;
+	Kern::Printf("WB::Write> pos_offset - %d", pos_offset) ;
+	Kern::Printf("WB::Write> size_block - %d", size_block) ;
+	Kern::Printf("WB::Write> size_offset - %d", size_offset) ;
+	#endif
+
+	TPtr8 des((ptrWriteBuf+pos_offset), l);
+		
+	if ( (r = iCurrentReq.ReadRemote(&des,0)) !=KErrNone)
+	{
+		return r;			
+	}
+
+
+	#ifdef _MEDWB_DEBUG_2_
+	Kern::Printf("WB::Write> local_pos - %d", local_pos) ;
+	Kern::Printf("WB::Write> w_block_size - %d", w_block_size) ;
+	#endif
+	
+	CyAsSymbianStorageDriver::Write(local_pos, w_block_size, ptrWriteBuf);
+	#ifdef INTERVAL_FOR_WB
+	NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	return r;
+	}
+
+
+TInt DMediaDriverWB::DoFormat(TLocDrvRequest& iCurrentReq)
+	{
+	Int64 pos = iCurrentReq.Pos();
+	Int64 length = iCurrentReq.Length();
+	TInt r;
+	if (length<0 || pos<0 || (pos+length)>KMaxTInt)
+		return KErrGeneral;
+	TInt p=(TInt)pos;
+	TInt l=(TInt)length;
+
+	if (p+l>CyAsSymbianStorageDriver::GetMediaSize())
+		return KErrGeneral;
+
+	#ifdef _MEDWB_DEBUG_1_
+	Kern::Printf("WB::Format> (%d@%d)", l, p);
+	#endif
+	#ifdef INTERVAL_FOR_WB
+	NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	TInt pos_block = p / iBlockSize;
+	TInt pos_offset =  p % iBlockSize;
+	TInt size_block = l / iBlockSize; 
+	TInt size_offset = l % iBlockSize; 
+	
+	TUint buf_offset = 0;
+	TInt	local_pos;
+	TInt	w_block_size = 0;
+
+	local_pos = pos_block;
+	
+	if( size_block )
+	{
+		CyAsSymbianStorageDriver::Read(local_pos, size_block, (void *)(ptrWriteBuf+buf_offset));
+		local_pos += size_block;
+		buf_offset += (size_block*iBlockSize);
+		w_block_size += size_block;
+	#ifdef INTERVAL_FOR_WB
+		NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	}
+	
+	if( pos_offset || size_offset )
+	{
+		CyAsSymbianStorageDriver::Read(local_pos, 1, (void *)(ptrWriteBuf+buf_offset) );
+		local_pos += size_block;
+		buf_offset += iBlockSize;
+		w_block_size ++;
+	#ifdef INTERVAL_FOR_WB
+		NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	}
+	
+	memclr(ptrWriteBuf + pos_offset, l);
+	
+	CyAsSymbianStorageDriver::Write(local_pos, w_block_size, ptrWriteBuf);
+	#ifdef INTERVAL_FOR_WB
+	NKern::Sleep(INTERVAL_FOR_WB);
+	#endif
+	return r;
+	}
+
+
+TInt DMediaDriverWB::PartitionInfo(TPartitionInfo& anInfo)
+//
+// Read the partition information for the media.  If the user supplied a password,
+// then unlock the card before trying to read the first sector.
+//
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf(">mmd:rpi");
+	#endif
+	iPartitionInfo = &anInfo;
+
+	// Assume MBR will be present or is not required
+	iMbrMissing = EFalse;
+
+	TInt r = DecodePartitionInfo();
+
+
+	if(r == KErrLocked)
+		{
+		// If the media is locked, we present a default partition entry to the local
+		// media subsystem, which will be updated when the media is finally unlocked.
+		r = CreateDefaultPartition();
+		if (r != KErrNone)
+			return r;
+		return KErrLocked;
+		}
+
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("<mmd:rpi:%d", r);
+	#endif
+	// KErrNone indicates asynchronous completion
+	return r;
+	}
+
+
+
+
+
+TInt DMediaDriverWB::DecodePartitionInfo()
+//
+// decode partition info that was read into internal buffer 
+//
+	{
+	TInt partitionCount=iPartitionInfo->iPartitionCount=0;
+	TInt defaultPartitionNumber=-1;
+	TMBRPartitionEntry* pe;
+	const TUint KMBRFirstPartitionOffsetAligned = KMBRFirstPartitionOffset & ~3;
+	TInt i;
+
+	CyAsSymbianStorageDriver::Read(0, 1, (void *)ptrReadBuf);
+	read_pos = 0;
+	read_size = 512;
+	// Read of the first sector successful so check for a Master Boot Record
+	if (*(TUint16*)(&ptrReadBuf[KMBRSignatureOffset])!=0xAA55)
+		goto mbr_done;
+
+	__ASSERT_COMPILE(KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry) <= KMBRSignatureOffset);
+
+	memmove(&ptrReadBuf[0], &ptrReadBuf[2],
+		KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry)); 
+
+
+	for (i=0, pe = (TMBRPartitionEntry*)(&ptrReadBuf[KMBRFirstPartitionOffsetAligned]);
+		pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++)
+		{
+		if (pe->IsDefaultBootPartition())
+			{
+			SetPartitionEntry(&iPartitionInfo->iEntry[0],pe->iFirstSector,pe->iNumSectors);
+			defaultPartitionNumber=i;
+			partitionCount++;
+			break;
+			}
+		}
+
+	// Now add any other partitions
+	for (i=0, pe = (TMBRPartitionEntry*)(&ptrReadBuf[KMBRFirstPartitionOffsetAligned]);
+		pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++)
+		{
+		TBool validPartition = ETrue;	// assume partition valid
+
+		if (defaultPartitionNumber==i)
+			{
+			// Already sorted
+			}
+
+		// FAT partition ?
+		else if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition())
+			{
+			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
+			#ifdef _MEDWB_DEBUG_1_
+			Kern::Printf("WB: FAT partition found at sector #%u", pe->iFirstSector);
+			#endif
+			partitionCount++;
+			}
+		else
+			{
+			validPartition = EFalse;
+			}
+		
+		if (validPartition && partitionCount == 1)
+			iHiddenSectors = pe->iFirstSector;
+
+		}
+
+	// Check the validity of the partition address boundaries
+	// If there is any
+	if(partitionCount > 0)
+		{
+		const TInt64 deviceSize = CyAsSymbianStorageDriver::GetMediaSize();
+		TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1];
+		// Check that the card address space boundary is not exceeded by the last partition
+		// In case of only 1 partition in the media check also it
+		if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize)
+			{
+			Kern::Printf("WB: MBR partition exceeds card memory space");
+			// Adjust the partition length to card address boundary
+			part.iPartitionLen = (deviceSize - part.iPartitionBaseAddr);
+
+			// Check that the base address contained valid information
+			if(part.iPartitionLen <= 0)
+				{
+				Kern::Printf("WB: Invalid base address");
+				// Invalid MBR - assume the boot sector is in the first sector
+				defaultPartitionNumber =-1; 
+				partitionCount=0;
+				}
+			}
+		// More than one partition. Go through all of them
+		if (partitionCount > 0)
+			{
+			for(i=partitionCount-1; i>0; i--)
+				{
+				const TPartitionEntry& curr = iPartitionInfo->iEntry[i];
+				TPartitionEntry& prev = iPartitionInfo->iEntry[i-1];
+				// Check if partitions overlap
+				if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen))
+					{
+					Kern::Printf("WB: Overlapping partitions");
+					// Adjust the partition length to not overlap the next partition
+					prev.iPartitionLen = (curr.iPartitionBaseAddr - prev.iPartitionBaseAddr);
+
+					// Check that the base address contained valid information
+					if(prev.iPartitionLen <= 0)
+						{
+						Kern::Printf("WB: Invalid base address");
+						// Invalid MBR - assume the boot sector is in the first sector
+						defaultPartitionNumber=(-1); 
+						partitionCount=0;
+						}
+					}
+				}
+			}
+		}
+
+mbr_done:
+	if (defaultPartitionNumber==(-1) && partitionCount==0)
+		{
+		Kern::Printf("WB:PartitionInfo no MBR");
+			{
+			// Assume it has no MBR, and the Boot Sector is in the 1st sector
+			SetPartitionEntry(&iPartitionInfo->iEntry[0],0,I64LOW(CyAsSymbianStorageDriver::GetMediaSize()>>KDiskSectorShift));
+			iHiddenSectors=0;
+			}
+		partitionCount=1;
+		}
+
+	iPartitionInfo->iPartitionCount=partitionCount;
+	iPartitionInfo->iMediaSizeInBytes=TotalSizeInBytes();
+	#ifdef _MEDWB_DEBUG_1_
+
+	Kern::Printf("<Mmc:PartitionInfo (C:%d)",iPartitionInfo->iPartitionCount);
+	Kern::Printf("     Partition1 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[0].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[0].iPartitionLen));
+	Kern::Printf("     Partition2 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[1].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[1].iPartitionLen));
+	Kern::Printf("     Partition3 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[2].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[2].iPartitionLen));
+	Kern::Printf("     Partition4 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[3].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[3].iPartitionLen));
+
+
+	Kern::Printf("     iMediaSizeInBytes (%d)",iPartitionInfo->iMediaSizeInBytes);
+	Kern::Printf("     iHiddenSectors (%d)",iHiddenSectors);
+	#endif
+
+	#ifdef _MEDWB_DEBUG_3_
+
+	TMBRPartitionEntry cPe;
+	if(GetDefaultPartitionInfo(cPe) == KErrNone)
+		{
+		pe = (TMBRPartitionEntry*)(&ptrReadBuf[0]);
+
+		Kern::Printf("-------------------------------------------");
+		Kern::Printf("-- Partition Entry Validation/Comparison --");
+		Kern::Printf("-------------------------------------------");
+		Kern::Printf("-- iX86BootIndicator [%02x:%02x] %c       -", pe->iX86BootIndicator, cPe.iX86BootIndicator, pe->iX86BootIndicator == cPe.iX86BootIndicator ? ' ' : 'X');
+		Kern::Printf("--        iStartHead [%02x:%02x] %c       -", pe->iStartHead,        cPe.iStartHead,        pe->iStartHead        == cPe.iStartHead        ? ' ' : 'X');
+		Kern::Printf("--      iStartSector [%02x:%02x] %c       -", pe->iStartSector,      cPe.iStartSector,      pe->iStartSector      == cPe.iStartSector      ? ' ' : 'X');
+		Kern::Printf("--    iStartCylinder [%02x:%02x] %c       -", pe->iStartCylinder,    cPe.iStartCylinder,    pe->iStartCylinder    == cPe.iStartCylinder    ? ' ' : 'X');
+		Kern::Printf("--    iPartitionType [%02x:%02x] %c       -", pe->iPartitionType,    cPe.iPartitionType,    pe->iPartitionType    == cPe.iPartitionType    ? ' ' : 'X');
+		Kern::Printf("--          iEndHead [%02x:%02x] %c       -", pe->iEndHead,          cPe.iEndHead,          pe->iEndHead          == cPe.iEndHead          ? ' ' : 'X');
+		Kern::Printf("--        iEndSector [%02x:%02x] %c       -", pe->iEndSector,        cPe.iEndSector,        pe->iEndSector        == cPe.iEndSector        ? ' ' : 'X');
+		Kern::Printf("--      iEndCylinder [%02x:%02x] %c       -", pe->iEndCylinder,      cPe.iEndCylinder,      pe->iEndCylinder      == cPe.iEndCylinder      ? ' ' : 'X');
+		Kern::Printf("--      iFirstSector [%08x:%08x] %c       -", pe->iFirstSector,      cPe.iFirstSector,      pe->iFirstSector      == cPe.iFirstSector      ? ' ' : 'X');
+		Kern::Printf("--       iNumSectors [%08x:%08x] %c       -", pe->iNumSectors,       cPe.iNumSectors,       pe->iNumSectors       == cPe.iNumSectors       ? ' ' : 'X');
+		Kern::Printf("-------------------------------------------");
+		}
+	#endif
+
+	return(KErrNone);
+	}
+
+
+TInt DMediaDriverWB::WritePartitionInfo()
+/**
+	Write the default partition table to freshly formatted media
+	@return Standard Symbian OS Error Code
+ */
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf(">mmd:wpi");
+	#endif
+	TMBRPartitionEntry partitionEntry;
+	TInt err = GetDefaultPartitionInfo(partitionEntry);
+	if(err == KErrNone)
+		{
+		TUint8	*iPartitionBuf;
+		
+		iPartitionBuf = new TUint8[KDiskSectorSize];
+		
+		#ifdef _MEDWB_DEBUG_2_
+		Kern::Printf("mmd:MBR/Partition Table");
+		Kern::Printf("    Boot ID          : %02xh", partitionEntry.iX86BootIndicator);
+		Kern::Printf("    Start Head       : %02xh", partitionEntry.iStartHead);
+		Kern::Printf("    Start Sector     : %02xh", partitionEntry.iStartSector);
+		Kern::Printf("    Start Cyclinder  : %02xh", partitionEntry.iStartCylinder);
+		Kern::Printf("    System ID        : %02xh", partitionEntry.iPartitionType);
+		Kern::Printf("    End Head         : %02xh", partitionEntry.iEndHead);
+		Kern::Printf("    End Sector       : %02xh", partitionEntry.iEndSector);
+		Kern::Printf("    End Cyclinder    : %02xh", partitionEntry.iEndCylinder);
+		Kern::Printf("    Relative Sector  : %08xh", partitionEntry.iFirstSector);
+		Kern::Printf("    Number of Sectors: %08xh", partitionEntry.iNumSectors);
+		#endif
+		//
+		// Clear all other partition entries and align the partition info into the minor buffer for writing...
+		//
+		memclr(iPartitionBuf, KDiskSectorSize);
+		memcpy(&iPartitionBuf[KMBRFirstPartitionEntry], &partitionEntry, sizeof(TMBRPartitionEntry));
+
+		*(TUint16*)(&iPartitionBuf[KMBRSignatureOffset]) = 0xAA55;
+
+		err = CyAsSymbianStorageDriver::Write(0, 1, iPartitionBuf);
+		
+		//
+		// Write the partition table and engage the read to validate and complete the mount process
+		//
+		delete iPartitionBuf;
+		iMbrMissing = EFalse;
+		}
+
+	#ifdef _MEDWB_DEBUG_3_
+	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:wpi:%d", err));
+	#endif
+	
+	return(err);
+	}
+
+
+TInt DMediaDriverWB::CreateDefaultPartition()
+	{
+	TMBRPartitionEntry defPartition;
+	TInt r = GetDefaultPartitionInfo(defPartition);
+	if (r == KErrNone)
+		{
+		SetPartitionEntry(&iPartitionInfo->iEntry[0], defPartition.iFirstSector, defPartition.iNumSectors);
+		iHiddenSectors = defPartition.iFirstSector;
+		iPartitionInfo->iPartitionCount   = 1;
+		iPartitionInfo->iMediaSizeInBytes = TotalSizeInBytes();
+		}
+	return r;
+	}
+
+TInt DMediaDriverWB::GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry)
+/**
+	Calculates the default patition information for an specific card.
+	@param aPartitionEntry The TMBRPartitionEntry to be filled in with the format parameters
+	@return Standard Symbian OS Error Code
+ */
+	{
+	memclr(&aPartitionEntry, sizeof(TMBRPartitionEntry));
+
+	const TUint32 KTotalSectors = I64LOW(CyAsSymbianStorageDriver::GetMediaSize() >> KDiskSectorShift);
+
+	aPartitionEntry.iFirstSector = (CyAsSymbianStorageDriver::GetEraseBlockSize()>> KDiskSectorShift);
+	aPartitionEntry.iNumSectors  = KTotalSectors - aPartitionEntry.iFirstSector;
+	aPartitionEntry.iX86BootIndicator = 0x00;
+
+	if(aPartitionEntry.iNumSectors < 32680)
+		{
+		aPartitionEntry.iPartitionType = KPartitionTypeFAT12;
+		}
+	else if(aPartitionEntry.iNumSectors < 65536)
+		{
+		aPartitionEntry.iPartitionType = KPartitionTypeFAT16small;
+		}
+	else if (aPartitionEntry.iNumSectors < 1048576)
+		{
+		aPartitionEntry.iPartitionType = KPartitionTypeFAT16;
+ 		}
+	else
+		{
+		aPartitionEntry.iPartitionType = KPartitionTypeWin95FAT32;
+		}
+	
+	return(KErrNone);
+	}
+
+void DMediaDriverWB::SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors)
+//
+// auxiliary static function to record partition information in TPartitionEntry object
+//
+	{
+	aEntry->iPartitionBaseAddr=aFirstSector;
+	aEntry->iPartitionBaseAddr<<=KDiskSectorShift;
+	aEntry->iPartitionLen=aNumSectors;
+	aEntry->iPartitionLen<<=KDiskSectorShift;
+	aEntry->iPartitionType=KPartitionTypeFAT12;	
+	}
+
+// ---- device status, callback DFC ----
+
+TInt DMediaDriverWB::CheckDevice(int aReqType)
+//
+// Check the device before initiating a command
+//
+	{
+	
+	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">wb:cd:%d",aReqType));
+
+	TInt r=KErrNone;
+#if 0
+	if (!iCard->IsReady())
+		r=KErrNotReady;
+
+	// The card must be locked if attempting to unlock during RPI, and
+	// unlocked at all other times.
+	else if (aReqType!=EMReqTypeUnlockPswd && iCard->IsLocked())
+		r=KErrLocked;
+	// Don't perform Password setting for WriteProtected cards, 
+	// unable to recover (ForcedErase) if password lost.
+	else if (aReqType==EMReqTypeChangePswd)
+		{
+		if (iCard->MediaType()==EMultiMediaROM)
+			{
+			r=KErrAccessDenied;
+			}
+		}
+	else if (iMbrMissing && aReqType==EMReqTypeNormalRd)
+		r=KErrCorrupt;
+
+	// Don't perform write operations when the mechanical write protect switch is set
+	else if (aReqType==EMReqTypeNormalWr && iCard->IsWriteProtected())
+		r=KErrAccessDenied;
+	// Don't perform write/format operations on MMC ROM cards
+	else if (iMediaType==EMultiMediaROM && aReqType == EMReqTypeNormalWr)
+		r=KErrAccessDenied;
+#endif
+	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<wb:cd:%d", r));
+	return(r);
+	}
+
+
+// ---- request management ----
+
+TInt DMediaDriverWB::Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo)
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf(">WB::Caps ");
+	#endif
+	// Fill buffer with current media caps.
+	aInfo.iType = EMediaHardDisk;
+	aInfo.iBattery = EBatNotSupported;
+	aInfo.iDriveAtt = KDriveAttLocal;
+	aInfo.iMediaAtt	= KMediaAttFormattable;
+
+	//if(CyAsSymbianStorageDriver::GetIsLocked())
+	//	aInfo.iMediaAtt |= KMediaAttLockable;
+	//if (iCard->HasPassword())
+		//aInfo.iMediaAtt |= KMediaAttHasPassword;
+		
+	if ( !CyAsSymbianStorageDriver::GetIsWriteable())
+		aInfo.iMediaAtt |= KMediaAttWriteProtected;
+	if (CyAsSymbianStorageDriver::GetIsLocked())
+		aInfo.iMediaAtt |= KMediaAttLocked;
+
+	aInfo.iFileSystemId = KDriveFileSysFAT;
+
+	// Format is performed in multiples of the erase sector (or multiple block) size
+	aInfo.iMaxBytesPerFormat =  CyAsSymbianStorageDriver::GetBlockSize();
+
+    // Set serial number to CID
+    aInfo.iSerialNumLength = 16;
+    for (TUint i=0; i<16; i++)
+        aInfo.iSerialNum[i] = 0;
+    
+	// Get block size & erase block size to allow the file system to align first usable cluster correctly
+	aInfo.iBlockSize = CyAsSymbianStorageDriver::GetBlockSize();
+	aInfo.iEraseBlockSize = CyAsSymbianStorageDriver::GetEraseBlockSize();
+
+	if ( CyAsSymbianStorageDriver::GetIsRemovable())
+		aInfo.iDriveAtt|= KDriveAttRemovable;
+
+	// Must return KErrCompletion to indicate that this 
+	// is a synchronous version of the function
+	return KErrNone;
+	}
+
+
+void DMediaDriverWB::NotifyPowerDown()
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf(">Mmc:NotifyPowerDown");
+	#endif
+
+	EndInCritical();
+
+	//CompleteRequest(KErrNotReady);
+	}
+
+void DMediaDriverWB::NotifyEmergencyPowerDown()
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf(">Ata:NotifyEmergencyPowerDown");
+	#endif
+	//TInt r=KErrNotReady;
+	//if (iCritical)
+	//	r=KErrAbort;
+	EndInCritical();
+
+	// need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once.
+
+	//CompleteRequest(r);
+	}
+
+TInt DMediaDriverWB::Request(TLocDrvRequest& aRequest)
+	{
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("MmcMd:Req %08x id %d",&aRequest,aRequest.Id());
+	#endif
+	TInt r=KErrNotSupported;
+	TInt id=aRequest.Id();
+
+	NKern::ThreadEnterCS();
+
+	TUint partitionType = aRequest.Drive()->iPartitionType;
+	TBool readOnly = (partitionType == KPartitionTypeRofs || partitionType == KPartitionTypeROM);
+
+	switch (id)
+		{
+		case DLocalDrive::ECaps:
+			{
+				TLocalDriveCapsV6& c = *(TLocalDriveCapsV6*)aRequest.RemoteDes();
+				TLocDrv& drive = *aRequest.Drive();
+				r = Caps(drive, c);
+				c.iSize = drive.iPartitionLen;
+				c.iPartitionType = drive.iPartitionType;	
+				c.iHiddenSectors = (TUint) (drive.iPartitionBaseAddr >> KDiskSectorShift);
+				#ifdef _MEDWB_DEBUG_2_
+				Kern::Printf("caps : c.iSize = %d ", c.iSize);
+				Kern::Printf("caps : c.iPartitionType = %d ", c.iPartitionType);
+				Kern::Printf("caps : c.iHiddenSectors = %d ", c.iHiddenSectors);
+				#endif
+			}
+			break;
+		case DLocalDrive::EQueryDevice:
+			Kern::Printf(">WB::EQueryDevice ");
+			r = KErrNotSupported;
+			break;
+
+		case DLocalDrive::ERead:
+			r=DoRead(aRequest);
+			break;
+		case DLocalDrive::EWrite:
+			if (readOnly)
+				return KErrNotSupported;
+			r=DoWrite(aRequest);
+			break;
+		case DLocalDrive::EFormat:
+			if (readOnly)
+				return KErrNotSupported;
+			r=DoFormat(aRequest);
+			break;
+
+
+		case DLocalDrive::EPasswordUnlock:
+		case DLocalDrive::EPasswordLock:
+		case DLocalDrive::EPasswordClear:
+		case DLocalDrive::EPasswordErase:
+		case DLocalDrive::EWritePasswordStore:
+				Kern::Printf(">WB::EPassword ");
+		break;
+		case DLocalDrive::EEnlarge:
+		case DLocalDrive::EReduce:
+			Kern::Printf(">WB::EReduce ");
+		default:
+			Kern::Printf(">WB::default ");
+			r=KErrNotSupported;
+			break;
+		}
+
+	NKern::ThreadLeaveCS();
+	#ifdef _MEDWB_DEBUG_3_
+	Kern::Printf("MmcMd:Req %08x cmp %d",&aRequest,r);
+	#endif
+	return r;
+	}
+
+void DMediaDriverWB::Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg)
+	{
+	// Complete using the default implementation
+	DMediaDriver::Disconnect(aLocalDrive, aMsg);
+	}
+
+
+DECLARE_EXTENSION_PDD()
+	{
+	// NB if the media driver has been defined as a kernel extension in the .OBY/.IBY file 
+	// i.e the "extension" keyword has been used rather than "device", then an instance of 
+	// DPhysicalDeviceMediaMmcFlash will already have been created by InitExtension(). In this 
+	// case the kernel will see that an object of the same name already exists and delete the 
+	// new one.
+	return new DPhysicalDeviceMediaWB;
+	}
+#ifdef REGIST_MEDIA_USE_MMC
+DECLARE_STANDARD_EXTENSION()
+	{	
+	Kern::Printf("Creating WestBridge PDD");
+
+	DPhysicalDeviceMediaWB* device = new DPhysicalDeviceMediaWB;
+
+	TInt r;
+	if (device==NULL)
+		r=KErrNoMemory;
+	else
+		r=Kern::InstallPhysicalDevice(device);
+	Kern::Printf("Installing WestBridge PDD in kernel returned %d",r);
+
+	if( CyAsSymbianStorageDriver::Open() )
+		Kern::Printf("**CyAsSymbianStorageDriver::Open() - Success");
+	else
+		Kern::Printf("**CyAsSymbianStorageDriver::Open() - Fail");
+
+	Kern::Printf("WestBridge extension entry point drive returns %d",r);
+	return r;
+	}
+
+#else
+static const TInt WBDriveNumbers[1]={1};	
+_LIT(KWBDriveName,"WestBridge");
+
+DECLARE_STANDARD_EXTENSION()
+	{
+	__KTRACE_OPT(KBOOT,Kern::Printf("Registering WB drive"));
+	#ifdef _MEDWB_DEBUG_2_
+	Kern::Printf("Registering WB drive");
+	#endif
+	TInt r=KErrNoMemory;
+	DPrimaryMediaBase* pM=new DPrimaryMediaBase;
+	if (pM)
+		{
+		r=LocDrv::RegisterMediaDevice(MEDIA_DEVICE_MMC,1,&WBDriveNumbers[0],pM,1,KWBDriveName);
+		}
+
+
+	if( CyAsSymbianStorageDriver::Open() )
+	{
+		#ifdef _MEDWB_DEBUG_1_
+		Kern::Printf("**CyAsSymbianStorageDriver::Open() - Success");
+		#endif
+	}
+	else
+	{
+		#ifdef _MEDWB_DEBUG_1_
+		Kern::Printf("**CyAsSymbianStorageDriver::Open() - Fail");
+		#endif
+	}
+	
+	__KTRACE_OPT(KBOOT,Kern::Printf("Registering WB drive - return %d",r));
+	#ifdef _MEDWB_DEBUG_2_
+	Kern::Printf("Registering WB drive - return %d",r);
+	#endif
+	
+	return r;
+	}
+
+
+#endif
+