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