/*
* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - contribution.
*
* Contributors:
* Gareth Long - Symbian Foundation
*
* Description: Minimalistic non volatile memory driver
*
*/
#include "locmedia.h"
#include "platform.h"
#include "variantmediadef.h"
#include "beagle_medstaticrd.h"
//#include "syborg.h"
#define NVMEM1_DRIVENAME "STATICRD"
#define NVMEM1_DRIVECOUNT 1
#define NVMEM1_DRIVELIST 1
#define NVMEM1_NUMMEDIA 1
_LIT(KNVMemPddName, "Media.MEDTATICRD");
_LIT(KNVMemDriveName,NVMEM1_DRIVENAME);
class DPhysicalDeviceMediaStaticRD : public DPhysicalDevice
{
public:
DPhysicalDeviceMediaStaticRD();
public:
// Implementing the interface
virtual TInt Install();
virtual void GetCaps(TDes8& aDes) const;
virtual TInt Create(DBase*& aChannel, TInt aMediaId, const TDesC8* anInfo, const TVersion& aVer);
virtual TInt Validate(TInt aDeviceType, const TDesC8* anInfo, const TVersion& aVer);
virtual TInt Info(TInt aFunction, TAny* a1);
};
class DMediaDriverStaticRD : public DMediaDriver
{
public:
DMediaDriverStaticRD(TInt aMediaId);
public:
// Implementing the interface
virtual TInt Request(TLocDrvRequest& aRequest);
virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg);
virtual TInt PartitionInfo(TPartitionInfo &anInfo);
virtual void NotifyPowerDown();
virtual void NotifyEmergencyPowerDown();
public:
void CompleteRequest(TInt aReason);
TInt DoCreate(TInt aMediaId);
TInt Caps(TLocDrvRequest& aRequest);
TInt Read();
TInt Write();
TInt Format();
static void TransactionLaunchDfc(TAny* aMediaDriver);
void DoTransactionLaunchDfc();
static void SessionEndDfc(TAny* aMediaDriver);
void DoSessionEndDfc();
TUint32 GetNVMemSize( void );
public:
TUint32 iLatestTransferSectorCount;
TDfc iSessionEndDfc;
private:
TInt ContinueTransaction( TUint32 aTransactionSectorOffset, TUint32 aTransactionSectorCount, TUint32 aDirection );
static void Isr(TAny* aPtr);
private:
TLocDrvRequest* iCurrentRequest; // Current Request
Int64 iTotalLength;
Int64 iProsessedLength;
Int64 iPos;
TPhysAddr iTransferBufferPhys;
TUint8* iTransferBufferLin;
TUint8* iDiscBufferLin;
TUint32 iHead;
TUint32 iTail;
TUint32 iSplitted;
TUint32 iAlignmentOverhead;
TBool iReadModifyWrite;
TDfc iTransactionLaunchDfc;
};
DPhysicalDeviceMediaStaticRD::DPhysicalDeviceMediaStaticRD()
//
// Constructor
//
{
__DEBUG_PRINT(">DPhysicalDeviceMediaStaticRD::DPhysicalDeviceMediaStaticRD");
iUnitsMask=0x1;
iVersion=TVersion(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
}
TInt DPhysicalDeviceMediaStaticRD::Install()
//
// Install the Internal NVMem PDD.
//
{
__DEBUG_PRINT("DPhysicalDeviceMediaStaticRD::Install()");
return SetName(&KNVMemPddName);
}
void DPhysicalDeviceMediaStaticRD::GetCaps(TDes8& /*aDes*/) const
//
// Return the media drivers capabilities.
//
{
__DEBUG_PRINT("DPhysicalDeviceMediaStaticRD::GetCaps()");
}
TInt DPhysicalDeviceMediaStaticRD::Create(DBase*& aChannel, TInt aMediaId, const TDesC8* /* anInfo */,const TVersion &aVer)
//
// Create an Internal Ram media driver.
//
{
__DEBUG_PRINT("DPhysicalDeviceMediaStaticRD::Create()");
if (!Kern::QueryVersionSupported(iVersion,aVer))
return KErrNotSupported;
TInt r=KErrNoMemory;
DMediaDriverStaticRD* pD=new DMediaDriverStaticRD(aMediaId);
aChannel=pD;
if (pD)
{
r=pD->DoCreate(aMediaId);
}
if( r==KErrNone )
{
pD->OpenMediaDriverComplete(KErrNone);
}
return r;
}
TInt DPhysicalDeviceMediaStaticRD::Validate(TInt aDeviceType, const TDesC8* /*anInfo*/, const TVersion& aVer)
{
__DEBUG_PRINT("DPhysicalDeviceMediaStaticRD::Validate()");
if (!Kern::QueryVersionSupported(iVersion,aVer))
return KErrNotSupported;
if (aDeviceType!=EFixedMedia1)
return KErrNotSupported;
return KErrNone;
}
TInt DPhysicalDeviceMediaStaticRD::Info(TInt aFunction, TAny*)
//
// Return the priority of this media driver
//
{
__DEBUG_PRINT("DPhysicalDeviceMediaStaticRD::Info()");
if (aFunction==EPriority)
return KMediaDriverPriorityNormal;
return KErrNotSupported;
}
DMediaDriverStaticRD::DMediaDriverStaticRD(TInt aMediaId)
//
// Constructor.
//
: DMediaDriver(aMediaId),
iSessionEndDfc(DMediaDriverStaticRD::SessionEndDfc, this, 1),
iTransferBufferPhys(0),
iTransactionLaunchDfc(DMediaDriverStaticRD::TransactionLaunchDfc, this, KMaxDfcPriority)
{
__DEBUG_PRINT("DMediaDriverStaticRD::DMediaDriverStaticRD()");
}
TInt DMediaDriverStaticRD::DoCreate(TInt /*aMediaId*/)
//
// Create the media driver.
//
{
__DEBUG_PRINT(">DMediaDriverStaticRD::DoCreate");
TInt r = KErrNone;
// Inform our size
Int64 size=GetNVMemSize()<<KDiskSectorShift;
if( size<=0 )
{
Kern::Fault("DMediaDriverStaticRD zero size nv memory array", 0);
}
SetTotalSizeInBytes(size);
// Some dfc initialization
if( r==KErrNone )
{
iSessionEndDfc.SetDfcQ( this->iPrimaryMedia->iDfcQ );
iTransactionLaunchDfc.SetDfcQ( this->iPrimaryMedia->iDfcQ );
}
// Create our piece of physically contiguous transfer buffer.
r = Epoc::AllocPhysicalRam( KNVMemTransferBufferSize, iTransferBufferPhys );
if( r != KErrNone )
{
Kern::Fault("DMediaDriverStaticRD Allocate Ram %d",r);
}
DPlatChunkHw* bufChunk = NULL;
DPlatChunkHw* bufChunk2 = NULL;
// Create HW Memory Chunk
r = DPlatChunkHw::New( bufChunk, iTransferBufferPhys, KNVMemTransferBufferSize, EMapAttrUserRw | EMapAttrFullyBlocking );
if( r != KErrNone )
{
// Check Physical Memory
if( iTransferBufferPhys )
{
// Free Physical Memory
Epoc::FreePhysicalRam( iTransferBufferPhys, KNVMemTransferBufferSize );
}
Kern::Fault("DMediaDriverStaticRD error in creating transfer buffer", r);
}
// Set Main Buffer Pointer
iTransferBufferLin = reinterpret_cast<TUint8*>(bufChunk->LinearAddress());
// Create HW Memory Chunk for drive image
r = DPlatChunkHw::New( bufChunk2, 0x81000000, 0x1000000, EMapAttrUserRw | EMapAttrFullyBlocking );
if( r != KErrNone )
{
Kern::Fault("DMediaDriverStaticRD error in creating disc image linear address", r);
}
// Set Main Buffer Pointer
iDiscBufferLin = reinterpret_cast<TUint8*>(bufChunk2->LinearAddress());
// Inform "hardware" about the shared memory
//WriteReg( KHwNVMemoryDevice, R_NVMEM_SHARED_MEMORY_BASE, iTransferBufferPhys );
//WriteReg( KHwNVMemoryDevice, R_NVMEM_SHARED_MEMORY_SIZE, KNVMemTransferBufferSize );
//WriteReg( KHwNVMemoryDevice, R_NVMEM_ENABLE, 1 );
// Set up interrupt service
//r = Interrupt::Bind( EIntNVMemoryDevice, Isr, this );
//Interrupt::Enable( EIntNVMemoryDevice );
__DEBUG_PRINT("<DMediaDriverStaticRD::DoCreate %d", r);
return(r);
}
TInt DMediaDriverStaticRD::Request(TLocDrvRequest& m)
{
TInt request=m.Id();
__DEBUG_PRINT(">DMediaDriverStaticRD::Request %d",request);
TInt r=KErrNone;
// Requests that can be handled synchronously
if( request == DLocalDrive::ECaps )
{
r=Caps(m);
return r;
}
// All other requests must be deferred if a request is currently in progress
if (iCurrentRequest)
{
// a request is already in progress, so hold on to this one
r = KMediaDriverDeferRequest;
}
else
{
iCurrentRequest=&m;
iProsessedLength = 0;
iHead = 0;
iTail = 0;
iSplitted = 0;
iAlignmentOverhead = 0;
iPos = m.Pos();
iTotalLength = m.Length();
__DEBUG_PRINT(">DMediaDriverStaticRD::Request pos:0x%lx len:0x%lx", iPos, iTotalLength);
if( iTotalLength<0 || iPos<0 )
{
Kern::Fault("DMediaDriverStaticRD::Request: illegal access!", 0);
}
// Handle unaligned operations
iHead = iPos % KDiskSectorSize;
TUint32 tailAlignment = ((iHead + iTotalLength) % KDiskSectorSize);
if( tailAlignment )
{
iTail = KDiskSectorSize - tailAlignment;
}
iSplitted = (iTotalLength + iHead + iTail) / KNVMemTransferBufferSize;
__DEBUG_PRINT(">DMediaDriverStaticRD::Request head: %d tail: %d splitted: %d\n", iHead, iTail, iSplitted );
__DEBUG_PRINT(">DMediaDriverStaticRD::Request partitionlen: %lx", iCurrentRequest->Drive()->iPartitionLen );
if( (iTotalLength + iPos) > iCurrentRequest->Drive()->iPartitionLen )
{
Kern::Fault("DMediaDriverStaticRD::Request: Access over partition boundary!", 0);
}
if( iTotalLength > KMaxTInt32 )
{
Kern::Fault("DMediaDriverStaticRD::Request: Access length overflow!", 0);
}
switch (request)
{
case DLocalDrive::ERead:
case DLocalDrive::EWrite:
case DLocalDrive::EFormat:
__DEBUG_PRINT("DMediaDriverStaticRD::Request iTransactionLaunchDfc.Enque()>");
iTransactionLaunchDfc.Enque();
__DEBUG_PRINT("DMediaDriverStaticRD::Request iTransactionLaunchDfc.Enque()<");
break;
case DLocalDrive::EEnlarge:
case DLocalDrive::EReduce:
default:
r=KErrNotSupported;
break;
}
}
__DEBUG_PRINT("<DMediaDriverStaticRD::Request %d",r);
return r;
}
void DMediaDriverStaticRD::CompleteRequest(TInt aReason)
//
// completes the request which is being currently processed
//
{
__DEBUG_PRINT("DMediaDriverStaticRD::CompleteRequest() reason: %d", aReason);
TLocDrvRequest* pR=iCurrentRequest;
if (pR)
{
iCurrentRequest=NULL;
DMediaDriver::Complete(*pR,aReason);
}
}
void DMediaDriverStaticRD::Disconnect( DLocalDrive* aLocalDrive, TThreadMessage* aMsg )
{
__DEBUG_PRINT(">DMediaDriverStaticRD::Disconnect()");
// Complete using the default implementation
DMediaDriver::Disconnect(aLocalDrive, aMsg);
__DEBUG_PRINT("<DMediaDriverStaticRD::Disconnect()");
}
void DMediaDriverStaticRD::NotifyPowerDown()
{
__DEBUG_PRINT("DMediaDriverStaticRD::NotifyPowerDown()");
// no action required
}
void DMediaDriverStaticRD::NotifyEmergencyPowerDown()
{
__DEBUG_PRINT("DMediaDriverStaticRD::NotifyEmergencyPowerDown()");
// no action required
}
TInt DMediaDriverStaticRD::Caps(TLocDrvRequest& m)
{
__DEBUG_PRINT("DMediaDriverStaticRD::Caps()");
TLocalDriveCapsV6& caps=*(TLocalDriveCapsV6*)m.RemoteDes();
caps.iType=EMediaHardDisk;
caps.iConnectionBusType=EConnectionBusInternal;
caps.iDriveAtt=KDriveAttLocal|KDriveAttInternal;
caps.iMediaAtt=KMediaAttFormattable;
caps.iFileSystemId=KDriveFileSysFAT;
caps.iPartitionType=KPartitionTypeFAT16;
caps.iSize=m.Drive()->iPartitionLen;
caps.iHiddenSectors=0;
caps.iEraseBlockSize = KNVMemTransferBufferSize;
caps.iBlockSize=KDiskSectorSize;
caps.iMaxBytesPerFormat = KNVMemTransferBufferSize;
return KErrCompletion;
}
TInt DMediaDriverStaticRD::Read()
{
__DEBUG_PRINT(">DMediaDriverStaticRD::Read() pos: %lx, size: %lx", iPos, iTotalLength);
// Set our sector offset
TUint32 transactionSectorOffset = (TUint32)(iPos / KDiskSectorSize);
TUint32 transactionLength = 0;
TUint32 transactionDirection = NVMEM_TRANSACTION_READ;
// Do we have an operation longer than our shared memory?
if( iSplitted > 0 )
{
transactionLength = KNVMemTransferBufferSize;
}
else
{
// Do the whole operation in one go since we have enough room in our memory
transactionLength = I64LOW(iTotalLength);
// Read the "broken" tail sector
if( iTail )
{
transactionLength += iTail;
iAlignmentOverhead += iTail;
}
}
// Read the "broken" head sector
if( iHead > 0 )
{
transactionLength += iHead;
iAlignmentOverhead += iHead;
}
// We should be ok to continue
ContinueTransaction( transactionSectorOffset, transactionLength/KDiskSectorSize, transactionDirection );
__DEBUG_PRINT("<DMediaDriverStaticRD::Read()");
return KErrNone;
}
TInt DMediaDriverStaticRD::Write()
{
__DEBUG_PRINT("DMediaDriverStaticRD::Write() pos: 0x%lx, size: 0x%lx", iPos, iTotalLength);
TInt r = KErrNone;
// Set our sector offset
TUint32 transactionSectorOffset = (TUint32)(iPos / KDiskSectorSize);
TUint32 transactionLength = 0;
TUint32 transactionDirection = NVMEM_TRANSACTION_WRITE;
// Do we have an operation longer than our shared memory?
if( iSplitted > 0 )
{
transactionLength = KNVMemTransferBufferSize;
}
else
{
// Do the whole operation in one go since we have enough room in our memory
transactionLength = I64LOW(iTotalLength);
if( iTail )
{
iReadModifyWrite = ETrue;
// Read the "broken" tail sector
transactionLength += iTail;
iAlignmentOverhead += iTail;
}
}
// Is there a need to read modify write the "broken" head sector of the operation
if( iHead > 0 )
{
iReadModifyWrite = ETrue;
// If splitted operation we only need the broken sector
if( iSplitted > 0 )
{
transactionLength = KDiskSectorSize;
iAlignmentOverhead += iHead;
}
else
{
// Read the "broken" head sector in addition to everything else
transactionLength += iHead;
iAlignmentOverhead += iHead;
}
}
// Was there a need to read-modify before writing
if( iReadModifyWrite )
{
transactionDirection = NVMEM_TRANSACTION_READ;
}
else
{
// Handle format here
if( iCurrentRequest->Id() == DLocalDrive::EFormat )
{
// Not much handling just flow through since we have filled the shared memory with zeroes already
}
else
{
// Read from client
TPtr8 targetDescriptor(iTransferBufferLin, transactionLength);
r = iCurrentRequest->ReadRemote(&targetDescriptor,0);
}
}
// We should be ok to continue
ContinueTransaction( transactionSectorOffset, transactionLength/KDiskSectorSize, transactionDirection );
return r;
}
TInt DMediaDriverStaticRD::Format()
{
__DEBUG_PRINT("DMediaDriverStaticRD::Format() pos: 0x%lx, size: 0x%lx", iPos, iTotalLength);
memset( iTransferBufferLin, 0x00, KNVMemTransferBufferSize );
// Stop the nonsense here. Write operations should be used for partial sector data removal operations
if( iHead > 0 || iTail > 0 )
{
Kern::Fault("DMediaDriverStaticRD::Format: alignment violation!", 0);
}
Write();
// DoTransaction( m, NVMEM_TRANSACTION_WRITE );
return KErrNone;
}
TInt DMediaDriverStaticRD::ContinueTransaction( TUint32 aTransactionSectorOffset, TUint32 aTransactionSectorCount, TUint32 aTransactionDirection )
{
__DEBUG_PRINT("DMediaDriverStaticRD::ContinueTransaction() sectoroffset: %d, sectorcount: %d, direction: %d", aTransactionSectorOffset, aTransactionSectorCount, aTransactionDirection);
if( aTransactionDirection != NVMEM_TRANSACTION_UNDEFINED )
{
//WriteReg( KHwNVMemoryDevice, R_NVMEM_TRANSACTION_OFFSET, aTransactionSectorOffset );
//WriteReg( KHwNVMemoryDevice, R_NVMEM_TRANSACTION_SIZE, aTransactionSectorCount );
//WriteReg( KHwNVMemoryDevice, R_NVMEM_TRANSACTION_DIRECTION, aTransactionDirection );
//WriteReg( KHwNVMemoryDevice, R_NVMEM_TRANSACTION_EXECUTE, aTransactionDirection );
if ( aTransactionDirection == NVMEM_TRANSACTION_WRITE )
{
memcpy( (TAny *)(iDiscBufferLin+(aTransactionSectorOffset<<9)), iTransferBufferLin, aTransactionSectorCount*512 );
}
else if ( aTransactionDirection == NVMEM_TRANSACTION_READ )
{
memcpy( iTransferBufferLin, (TAny *)(iDiscBufferLin+(aTransactionSectorOffset<<9)), aTransactionSectorCount*512 );
}
iLatestTransferSectorCount = aTransactionSectorCount;
// Isr(this); // terrible hack, we've yransferred all the sectors and now we pretend to generate an interrupt
iSessionEndDfc.Enque();
}
else
{
Kern::Fault("DMediaDriverStaticRD::ContinueTransaction: Undefined transaction!", 0);
}
return KErrNone;
}
TInt DMediaDriverStaticRD::PartitionInfo(TPartitionInfo& anInfo)
//
// Return partition information on the media.
//
{
__DEBUG_PRINT("DMediaDriverStaticRD::PartitionInfo()");
anInfo.iPartitionCount=1;
anInfo.iEntry[0].iPartitionBaseAddr=0;
anInfo.iEntry[0].iPartitionLen=anInfo.iMediaSizeInBytes=TotalSizeInBytes();
anInfo.iEntry[0].iPartitionType=KPartitionTypeFAT16;
return KErrCompletion;
}
void DMediaDriverStaticRD::TransactionLaunchDfc(TAny* aMediaDriver)
{
static_cast<DMediaDriverStaticRD*>(aMediaDriver)->DoTransactionLaunchDfc();
}
void DMediaDriverStaticRD::DoTransactionLaunchDfc()
{
__DEBUG_PRINT(">DMediaDriverStaticRD::DoTransactionLaunchDfc()");
TInt request = iCurrentRequest->Id();
TInt r(KErrNone);
switch (request)
{
case DLocalDrive::ERead:
r=Read();
break;
case DLocalDrive::EWrite:
r=Write();
break;
case DLocalDrive::EFormat:
r=Format();
break;
case DLocalDrive::EEnlarge:
case DLocalDrive::EReduce:
default:
r=KErrNotSupported;
break;
}
if( r != KErrNone )
{
// TODO some proper error handling here
}
__DEBUG_PRINT("<MediaDriverStaticRD::DoTransactionLaunchDfc %d",r);
}
void DMediaDriverStaticRD::SessionEndDfc(TAny* aMediaDriver)
{
static_cast<DMediaDriverStaticRD*>(aMediaDriver)->DoSessionEndDfc();
}
void DMediaDriverStaticRD::DoSessionEndDfc()
{
__DEBUG_PRINT(">DMediaDriverStaticRD::DoSessionEndDfc()");
TInt r = KErrNone;
// Check that we have a request in process
if( iCurrentRequest )
{
// Transaction variables
TUint32 transactionSectorOffset(0);
TUint32 transactionLength(0);
TUint32 transactionDirection( NVMEM_TRANSACTION_UNDEFINED );
// How much did we actually transfer?
TUint32 latestTransferSize = (iLatestTransferSectorCount * KDiskSectorSize);
__DEBUG_PRINT("DMediaDriverStaticRD::DoSessionEndDfc() latestTransferSize: %d", latestTransferSize );
// Subtract alignment overhead
latestTransferSize = latestTransferSize - iAlignmentOverhead;
// For decision whether the buffer is ready for operation already
TBool bufferReady(EFalse);
// For decision whether we have finished the latest request
TBool sessionComplete(EFalse);
// Was there a read-modify-write (RWM) for which we need to do some buffer manipulation before proceeding?
// Note that in case of format we triggered to alignment violation in earlier method already and can not enter to following
// condition when there is a format operation going on
if( iReadModifyWrite )
{
bufferReady = ETrue;
iReadModifyWrite = EFalse;
// Was it a splitted operation for which we only need to take care of the broken head sector.
if( iSplitted > 0 )
{
// We have a sector here here filled with data from mass memory. Modify with client data.
__DEBUG_PRINT("DMediaDriverStaticRD::DoSessionEndDfc() readremote splitted: %d head: %d", latestTransferSize, iHead );
TPtr8 targetDescriptor(&iTransferBufferLin[iHead], KNVMemTransferBufferSize - iHead);
r = iCurrentRequest->ReadRemote(&targetDescriptor,0);
}
// Else we need to take care of both head and tail
else
{
// We have a piece of data read from mass memory. Modify with client data.
__DEBUG_PRINT("DMediaDriverStaticRD::DoSessionEndDfc() readremote: %d head: %d", I64LOW(iTotalLength - iProsessedLength), iHead );
TPtr8 targetDescriptor(&iTransferBufferLin[iHead], I64LOW(iTotalLength - iProsessedLength));
r = iCurrentRequest->ReadRemote(&targetDescriptor,0);
// latestTransferSize -= (KDiskSectorSize - iTail);
iTail = 0;
}
}
else
{
// Overhead is processed when we enter here
iAlignmentOverhead = 0;
// Update position
iPos += latestTransferSize;
// Save the information on how many bytes we transferred already
iProsessedLength += latestTransferSize;
// Update the splitted information. We don't take head into account here anymore since it is already taken care of
iSplitted = (iTotalLength - iProsessedLength + iTail) / KNVMemTransferBufferSize;
// Check if we have done already
if( iProsessedLength >= iTotalLength )
{
// If this was the final transfer for this request let's take tail into account as well (if not taken already)
// iProsessedLength -= iTail;
// latestTransferSize -= iTail;
if( iProsessedLength > iTotalLength )
{
Kern::Fault("DMediaDriverStaticRD: Illegal transfer operation!", 0);
}
sessionComplete = ETrue;
}
}
TInt request = iCurrentRequest->Id();
// Set our sector offset
transactionSectorOffset = (TUint32)(iPos / KDiskSectorSize);
if( bufferReady )
{
// Write as much as we read in RMW operation
transactionLength = (iLatestTransferSectorCount * KDiskSectorSize);
}
else
{
// Do we have an operation longer than our shared memory?
if( iSplitted > 0 )
{
transactionLength = KNVMemTransferBufferSize;
}
else
{
// Do the whole operation in one go since we have enough room in our memory
transactionLength = I64LOW(iTotalLength - iProsessedLength);
// Read the "broken" tail sector
if( iTail > 0 && request == DLocalDrive::EWrite )
{
iReadModifyWrite = ETrue;
// Read the "broken" tail sector
transactionLength += iTail;
iAlignmentOverhead = iTail;
}
}
}
// Was there a need to read-modify before writing
if( iReadModifyWrite )
{
transactionDirection = NVMEM_TRANSACTION_READ;
}
else
{
if( request == DLocalDrive::ERead )
{
transactionDirection = NVMEM_TRANSACTION_READ;
// Write to client
__DEBUG_PRINT("DMediaDriverStaticRD::DoSessionEndDfc() WriteRemote: %d head: %d", latestTransferSize, iHead );
TPtrC8 sourceDescriptor(&iTransferBufferLin[iHead], latestTransferSize);
r = iCurrentRequest->WriteRemote( &sourceDescriptor, 0 );
}
// Head is processed
iHead = 0;
if( request == DLocalDrive::EWrite && !sessionComplete )
{
transactionDirection = NVMEM_TRANSACTION_WRITE;
if( bufferReady )
{
// Actually no need for any actions here
}
else
{
// Prepare a buffer for transfer
__DEBUG_PRINT("DMediaDriverStaticRD::DoSessionEndDfc() ReadRemote: %d head: %d", latestTransferSize, iHead );
TPtr8 targetDescriptor(iTransferBufferLin, transactionLength);
r = iCurrentRequest->ReadRemote(&targetDescriptor,0);
}
}
if( request == DLocalDrive::EFormat )
{
transactionDirection = NVMEM_TRANSACTION_WRITE;
}
}
if( sessionComplete )
{
CompleteRequest( r );
}
else
{
ContinueTransaction( transactionSectorOffset, transactionLength/KDiskSectorSize, transactionDirection );
}
}
else
{
// Let's just flow through for now
}
__DEBUG_PRINT("<DMediaDriverStaticRD::DoSessionEndDfc()" );
}
TUint32 DMediaDriverStaticRD::GetNVMemSize( void )
{
__DEBUG_PRINT("DMediaDriverStaticRD::GetNVMemSize()");
TUint32 sizeInSectors = 32768;//ReadReg( KHwNVMemoryDevice, R_NVMEM_NV_MEMORY_SIZE );
return sizeInSectors;
}
void DMediaDriverStaticRD::Isr(TAny* aPtr)
{
__DEBUG_PRINT(">DMediaDriverStaticRD::Isr");
DMediaDriverStaticRD* nvMem = reinterpret_cast<DMediaDriverStaticRD*>(aPtr);
// Save the amount of transferred sectors. This clears the interrupt from HW as well
//nvMem->iLatestTransferSectorCount = ReadReg( KHwNVMemoryDevice, R_NVMEM_STATUS );
// Clear from framework
//Interrupt::Clear( EIntNVMemoryDevice );
nvMem->iSessionEndDfc.Add();
}
DECLARE_EXTENSION_PDD()
{
__DEBUG_PRINT(">MediaDriverStaticRD create device");
return new DPhysicalDeviceMediaStaticRD;
}
static const TInt NVMemDriveNumbers[NVMEM1_DRIVECOUNT]={NVMEM1_DRIVELIST};
DECLARE_STANDARD_EXTENSION()
{
__DEBUG_PRINT("Registering STATICRD drive");
TInt r=KErrNoMemory;
DPrimaryMediaBase* pM=new DPrimaryMediaBase;
TDynamicDfcQue* NVMemoryDfcQ;
r = Kern::DynamicDfcQCreate( NVMemoryDfcQ, KNVMemDfcThreadPriority, KNVMemDriveName );
if( r == KErrNone )
{
pM->iDfcQ = NVMemoryDfcQ;
}
else
{
__DEBUG_PRINT("NVMEM DFCQ initialization failed");
}
if (pM)
{
r=LocDrv::RegisterMediaDevice(EFixedMedia1,NVMEM1_DRIVECOUNT,&NVMemDriveNumbers[0],pM,NVMEM1_NUMMEDIA,KNVMemDriveName);
}
pM->iMsgQ.Receive();
__DEBUG_PRINT("Registering NVMEM drive - return %d",r);
return r;
}