omap3530/beagle_drivers/medwb/medwb.cpp
author arunabha
Wed, 03 Mar 2010 13:10:32 +0000
changeset 23 117faf51deac
child 33 2905910218db
permissions -rw-r--r--
Bug 1996 - Contribution for West Bridge Astoria Symbian Storage Driver this storage driver is for the West Bridge Astoria chipset. This device has a USB, SD and processor port for communication with a baseband processor. In our port, we connected this device DVK to the Beagleboard through the SPI interface of the OMAP3. After driver installation, the Symbian OS can see an external device or D: drive represented by the SD card. In this driver, the USB interface is not used directly, though this may be the subject of future contributions. The appropriate way to test the driver is to access the external volume and do file read and write to it, pretty much the same way you would test a thumb drive on your PC

/* 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