Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// Copyright (c) 1998-2009 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 - initial contribution.
//
// Contributors:
//
// Description:
// e32\drivers\locmedia\locmedia.cpp
//
//
#include "locmedia.h"
#include <d32locd.h>
#include "dmasupport.h"
#include <kernel/cache.h>
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "locmedia_ost.h"
#ifdef __VC32__
#pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
#endif
#include "locmediaTraces.h"
#endif
#if defined(_DEBUG) && defined(__DEMAND_PAGING__)
//#define __DEBUG_DEMAND_PAGING__
#endif
#if 0
#define CHECK_RET(r) if ((r)==KErrNotSupported && (KDebugNum(KSCRATCH))) {NKern::Lock(); *(TInt*)0xfaece5=0;}
//#define CHECK_RET(r)
#else
#define CHECK_RET(r)
#endif
_LIT(KLddName,"LocDrv");
_LIT(KLitMediaDriverName, "Media.*");
_LIT(KLitLocMedia,"LocMedia");
#define LOCM_FAULT() Kern::Fault("LOCMEDIA",__LINE__)
const TInt KMaxLocalDriveCapsLength=256;
const TInt KMaxQueryDeviceLength=256;
// The maximum amount of user-data which will be pinned. If a request is longer
// than this value it will be split up into a number of requests
// This value is a bit arbitrary - it needs to be sufficiently large so that transfer
// rates don't suffer too much - but it can't be too big or we'd be "stealing" too much
// memory from the demand paging pool and starving other processes
const TInt KMaxPinData = 256*1024;
// The number of locks available for pinning shared by all the drive threads in the system.
// If all locks are in use then a single pre-allocated lock is used.
const TInt KDynamicPagingLockCount = 8;
TLocDrv* TheDrives[KMaxLocalDrives];
DMedia* TheMedia[KMaxLocalDrives];
HBuf* DriveNames[KMaxLocalDrives];
TInt UsedMedia=0;
TPasswordStore* ThePasswordStore=NULL;
class DPrimaryMediaBase::DBody : public DBase
{
public:
TInt iPhysDevIndex;
TInt iRequestCount;
#ifdef __DEMAND_PAGING__
DMediaPagingDevice* iPagingDevice;
TInt iPageSizeMsk; // Mask of page size (e.g. 4096-1 -> 4095)
TInt iMediaChanges;
#endif
};
#ifdef __DEMAND_PAGING__
DMediaPagingDevice* ThePagingDevices[KMaxLocalDrives];
DPrimaryMediaBase* TheRomPagingMedia = NULL;
DPrimaryMediaBase* TheDataPagingMedia = NULL;
TBool DataPagingDeviceRegistered = EFalse;
class DPinObjectAllocator;
DPinObjectAllocator* ThePinObjectAllocator = NULL;
// The paging media might share a DfcQ with other non-paging media (e.g. 2 MMC/SD cards sharing the same stack)
// In this case, we need to avoid taking page faults on the non-paging media too, hence the need for these checks:
inline TBool DataPagingDfcQ(DPrimaryMediaBase* aPrimaryMedia)
{return TheDataPagingMedia && TheDataPagingMedia->iDfcQ == aPrimaryMedia->iDfcQ;}
inline TBool RomPagingDfcQ(DPrimaryMediaBase* aPrimaryMedia)
{return TheRomPagingMedia && TheRomPagingMedia->iDfcQ == aPrimaryMedia->iDfcQ;}
/*
DPinObjectAllocator
Internal class which contains :
(1) a queue of pre-allocated TVirtualPinObject's;
(2) a single pre-allocated DFragmentationPagingLock object:
this may be used if there are no TVirtualPinObject's available or if Kern::PinVirtualMemory() fails
*/
NONSHARABLE_CLASS(DPinObjectAllocator) : public DBase
{
public:
/*
SVirtualPinContainer
Internal class encapsulating a TVirtualPinObject.
Contains a SDblQueLink so that it may form part of a SDblQue
*/
typedef struct
{
TVirtualPinObject* iObject;
SDblQueLink iLink;
} SVirtualPinContainer;
public:
inline DPinObjectAllocator() {};
~DPinObjectAllocator();
TInt Construct(TInt aObjectCount, TUint aNumPages);
SVirtualPinContainer* AcquirePinObject();
void ReleasePinObject(SVirtualPinContainer* aVirtualPinObject);
inline DFragmentationPagingLock& PreAllocatedDataLock() {return *iPreAllocatedDataLock;}
private:
// array of SVirtualPinContainer's
SVirtualPinContainer* iVirtualPinContainers;
TInt iObjectCount;
// queues containing SVirtualPinContainer's
SDblQue iFreeQ;
// pre-allocated (small) buffers for locking client data should Kern::PinVirtualMemory() fail
DFragmentationPagingLock* iPreAllocatedDataLock;
// A mutex to protect access to the pinning objects.
NFastMutex iLock;
public:
TUint iFragmentGranularity;
};
DPinObjectAllocator::~DPinObjectAllocator()
{
OstTraceFunctionEntry1( DPINOBJECTALLOCATOR_DPINOBJECTALLOCATOR_ENTRY, this );
if (iPreAllocatedDataLock)
{
iPreAllocatedDataLock->Cleanup();
delete iPreAllocatedDataLock;
}
for (TInt n=0; n<iObjectCount; n++)
{
SVirtualPinContainer& virtualPinContainer = iVirtualPinContainers[n];
if (virtualPinContainer.iObject)
Kern::DestroyVirtualPinObject(virtualPinContainer.iObject);
}
delete [] iVirtualPinContainers;
OstTraceFunctionExit1( DPINOBJECTALLOCATOR_DPINOBJECTALLOCATOR_EXIT, this );
}
TInt DPinObjectAllocator::Construct(TInt aObjectCount, TUint aNumPages)
{
OstTraceFunctionEntryExt( DPINOBJECTALLOCATOR_CONSTRUCT_ENTRY, this );
TInt pageSize = Kern::RoundToPageSize(1);
iFragmentGranularity = pageSize * aNumPages;
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation granularity set to 0x%x", iFragmentGranularity));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPINOBJECTALLOCATOR_CONSTRUCT, "Fragmentation granularity=0x%x", iFragmentGranularity);
// construct the paging lock containing pre-allocated buffers
iPreAllocatedDataLock = new DFragmentationPagingLock();
if(!iPreAllocatedDataLock)
{
OstTraceFunctionExitExt( DPINOBJECTALLOCATOR_CONSTRUCT_EXIT1, this, KErrNoMemory );
return KErrNoMemory;
}
TInt r = iPreAllocatedDataLock->Construct(aNumPages);
if (r != KErrNone)
{
OstTraceFunctionExitExt( DPINOBJECTALLOCATOR_CONSTRUCT_EXIT2, this, r );
return r;
}
SVirtualPinContainer* iVirtualPinContainers = new SVirtualPinContainer[aObjectCount];
if (iVirtualPinContainers == NULL)
{
OstTraceFunctionExitExt( DPINOBJECTALLOCATOR_CONSTRUCT_EXIT3, this, KErrNoMemory );
return KErrNoMemory;
}
memclr(iVirtualPinContainers, sizeof(SVirtualPinContainer) * aObjectCount);
iObjectCount = aObjectCount;
// construct the queue of dynamic paging locks
for (TInt n=0; n<aObjectCount; n++)
{
SVirtualPinContainer& pinContainer = iVirtualPinContainers[n];
TInt r = Kern::CreateVirtualPinObject(pinContainer.iObject);
if (r != KErrNone)
{
OstTraceFunctionExitExt( DPINOBJECTALLOCATOR_CONSTRUCT_EXIT4, this, KErrNoMemory );
return KErrNoMemory;
}
iFreeQ.Add(&pinContainer.iLink);
}
OstTraceFunctionExitExt( DPINOBJECTALLOCATOR_CONSTRUCT_EXIT5, this, KErrNone );
return KErrNone;
}
/**
returns a SVirtualPinContainer object or NULL if NULL available
*/
DPinObjectAllocator::SVirtualPinContainer* DPinObjectAllocator::AcquirePinObject()
{
OstTraceFunctionEntry1( DPINOBJECTALLOCATOR_ACQUIREPINOBJECT_ENTRY, this );
SVirtualPinContainer* pinContainer = NULL;
NKern::FMWait(&iLock);
if (!iFreeQ.IsEmpty())
{
SDblQueLink* link = iFreeQ.First();
pinContainer = _LOFF(link, SVirtualPinContainer, iLink);
link->Deque();
}
NKern::FMSignal(&iLock);
OstTraceFunctionExit1( DPINOBJECTALLOCATOR_ACQUIREPINOBJECT_EXIT, this );
return pinContainer;
}
/**
returns a SVirtualPinContainer object to the pool
*/
void DPinObjectAllocator::ReleasePinObject(SVirtualPinContainer* aPinContainer)
{
OstTraceFunctionEntry1( DPINOBJECTALLOCATOR_RELEASEPINOBJECT_ENTRY, this );
NKern::FMWait(&iLock);
iFreeQ.Add(&aPinContainer->iLink);
NKern::FMSignal(&iLock);
OstTraceFunctionExit1( DPINOBJECTALLOCATOR_RELEASEPINOBJECT_EXIT, this );
}
#endif // __DEMAND_PAGING__
/********************************************
* Local drive device base class
********************************************/
DECLARE_EXTENSION_LDD()
{
return new DLocalDriveFactory;
}
DLocalDriveFactory::DLocalDriveFactory()
//
// Constructor
//
{
OstTraceFunctionEntry1( DLOCALDRIVEFACTORY_DLOCALDRIVEFACTORY_ENTRY, this );
iParseMask=KDeviceAllowUnit|KDeviceAllowInfo;
iUnitsMask=~(0xffffffff<<KMaxLocalDrives);
iVersion=TVersion(KLocalDriveMajorVersion,KLocalDriveMinorVersion,KLocalDriveBuildVersion);
OstTraceFunctionExit1( DLOCALDRIVEFACTORY_DLOCALDRIVEFACTORY_EXIT, this );
}
TInt DLocalDriveFactory::Install()
//
// Install the device driver.
//
{
return SetName(&KLddName);
}
void DLocalDriveFactory::GetCaps(TDes8& /*aDes*/) const
//
// Return the Comm capabilities.
//
{
// TCapsLocalDriveV01 b;
// b.version=iVersion;
// aDes.FillZ(aDes.MaxLength());
// aDes.Copy((TUint8 *)&b,Min(aDes.MaxLength(),sizeof(b)));
}
TInt DLocalDriveFactory::Create(DLogicalChannelBase*& aChannel)
//
// Create a channel on the device.
//
{
OstTraceFunctionEntry1( DLOCALDRIVEFACTORY_CREATE_ENTRY, this );
aChannel=new DLocalDrive;
return aChannel?KErrNone:KErrNoMemory;
}
/********************************************
* Local drive interface class
********************************************/
DLocalDrive::DLocalDrive()
{
// iLink.iNext=NULL;
}
DLocalDrive::~DLocalDrive()
{
OstTraceFunctionEntry1( DLOCALDRIVE_DLOCALDRIVE_ENTRY, this );
if (iDrive)
{
__KTRACE_OPT(KLOCDRV,Kern::Printf(">DLocalDrive::DoClose D:%d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
iDrive->Disconnect(this);
__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive::DoClose D:%d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
}
DThread* pC=NULL;
NKern::LockSystem();
if (iCleanup.iThread)
{
pC=iCleanup.iThread;
iCleanup.Remove();
iCleanup.iThread=NULL;
}
NKern::UnlockSystem();
if (pC) // original client may already have terminated
{
if (iNotifyChangeRequest)
Kern::QueueRequestComplete(pC,iNotifyChangeRequest,KErrCancel);
pC->Close(NULL); // balances Open() in DoCreate
}
if (iNotifyChangeRequest)
Kern::DestroyClientRequest(iNotifyChangeRequest);
OstTraceFunctionExit1( DLOCALDRIVE_DLOCALDRIVE_EXIT, this );
}
TInt DLocalDrive::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer)
{
OstTraceFunctionEntry1( DLOCALDRIVE_DOCREATE_ENTRY, this );
if(!Kern::CurrentThreadHasCapability(ECapabilityTCB,__PLATSEC_DIAGNOSTIC_STRING("Checked by ELOCD.LDD (Local Media Driver)")))
{
OstTraceFunctionExitExt( DLOCALDRIVE_DOCREATE_EXIT1, this, KErrPermissionDenied );
return KErrPermissionDenied;
}
if (!Kern::QueryVersionSupported(TVersion(KLocalDriveMajorVersion,KLocalDriveMinorVersion,KLocalDriveBuildVersion),aVer))
{
OstTraceFunctionExitExt( DLOCALDRIVE_DOCREATE_EXIT2, this, KErrNotSupported );
return KErrNotSupported;
}
NKern::ThreadEnterCS();
TInt r = Kern::CreateClientDataRequest(iNotifyChangeRequest);
NKern::ThreadLeaveCS();
if (r != KErrNone)
{
OstTraceFunctionExitExt( DLOCALDRIVE_DOCREATE_EXIT3, this, r );
return r;
}
DThread& t=Kern::CurrentThread();
NKern::LockSystem();
t.AddCleanup(&iCleanup);
NKern::UnlockSystem();
t.Open();
iNotifyChangeRequest->SetDestPtr((TBool*) anInfo);
iDrive=TheDrives[aUnit];
if (!iDrive)
{
OstTraceFunctionExitExt( DLOCALDRIVE_DOCREATE_EXIT4, this, KErrNotSupported );
return KErrNotSupported;
}
__KTRACE_OPT(KLOCDRV,Kern::Printf("DLocalDrive Create - connect to drive %d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
r=iDrive->Connect(this);
__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive Create D:%d, M:%08x r:%d",iDrive->iDriveNumber,iDrive->iMedia,r));
if (r!=KErrNone)
iDrive=NULL; // didn't connect so don't disconnect
OstTraceFunctionExitExt( DLOCALDRIVE_DOCREATE_EXIT5, this, r );
return r;
}
#if defined(_DEBUG)
void DebugDumpDriveCaps(const TLocDrv* aDrive, const TAny* aCaps)
{
const TLocalDriveCapsV5& c=*(const TLocalDriveCapsV5*)aCaps;
Kern::Printf("Drive %d Caps:", aDrive->iDriveNumber);
Kern::Printf("Size: %lx", c.iSize);
Kern::Printf("Type: %08x", c.iType);
Kern::Printf("Bus : %08x", c.iConnectionBusType);
Kern::Printf("DAtt: %08x", c.iDriveAtt);
Kern::Printf("MAtt: %08x", c.iMediaAtt);
Kern::Printf("Base: %08x", c.iBaseAddress);
Kern::Printf("FSID: %04x", c.iFileSystemId);
Kern::Printf("PTYP: %04x", c.iPartitionType);
Kern::Printf("HIDN: %08x", c.iHiddenSectors);
Kern::Printf("EBSZ: %08x", c.iEraseBlockSize);
//---------------- V5 ------------------//
if (c.iSerialNumLength != 0)
{
Kern::Printf("SN: length is %d", c.iSerialNumLength);
TBuf8<2*KMaxSerialNumLength+20> snBuf;
snBuf.Append(_L8("SN: content is "));
for (TUint i=0; i<c.iSerialNumLength; i++)
snBuf.AppendNumFixedWidth(c.iSerialNum[i], EHex, 2);
Kern::Printf((const char*)snBuf.Ptr());
}
else
Kern::Printf("SN: not supported");
}
#endif
/*
* Requests are passed in message as follows:
* iValue = request ID
* iArg[0,1]= Position
* iArg[2,3]= Length
* iArg[4] = Pointer to remote thread (NULL if client)
* iArg[5] = Pointer to remote descriptor
* iArg[6] = Offset into remote descriptor
* iArg[7] = Flags (whole media)
* iArg[8] = Pointer to TLocDrv
*/
TInt DLocalDrive::Request(TInt aFunction, TAny* a1, TAny* a2)
{
OstTraceFunctionEntry1( DLOCALDRIVE_REQUEST_ENTRY, this );
__TRACE_TIMING(0);
__KTRACE_OPT(KLOCDRV,Kern::Printf(">DLocalDrive::DoControl D:%d M:%08x F:%d A1:%08x A2:%08x",
iDrive->iDriveNumber, iDrive->iMedia, aFunction, a1, a2));
OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST, "iMedia=0x%08x; iDriveNumber=%d; Request Id=%d", (TUint) iDrive->iMedia, (TInt) iDrive->iDriveNumber, (TInt) aFunction );
TInt r=KErrNotSupported;
TLocDrvRequest& m=TLocDrvRequest::Get();
m.Flags()=0;
m.Drive()=iDrive;
switch (aFunction)
{
case RLocalDrive::EControlRead:
{
m.Id()=ERead;
r=m.ProcessMessageData(a1);
__TRACE_TIMING(1);
if (r==KErrNone)
{
__TRACE_TIMING(2);
OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_READ, "ERead iDriveNumber=%d; length=0x%x; position=0x%x; TLocDrvRequest Object=0x%x", (TInt) iDrive->iDriveNumber, (TUint) m.Length(), (TUint) m.Pos(), (TUint) &m);
r=iDrive->Request(m);
__TRACE_TIMING(3);
OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_READ_RETURN, "ERead Return iDriveNumber=%d; length=0x%x; position=0x%x; TLocDrvRequest Object=0x%x", (TInt) iDrive->iDriveNumber, (TUint) m.Length(), (TUint) m.Pos(), (TUint) &m );
}
m.CloseRemoteThread();
break;
}
case RLocalDrive::EControlWrite:
{
m.Id()=EWrite;
r=m.ProcessMessageData(a1);
if (r==KErrNone)
{
OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_WRITE, "EWrite iDriveNumber=%d; length=0x%x; position=0x%x; TLocDrvRequest Object=0x%x", (TInt) iDrive->iDriveNumber, (TUint) m.Length(), (TUint) m.Pos(), (TUint) &m );
r=iDrive->Request(m);
OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_WRITE_RETURN, "EWrite Return iDriveNumber=%d; length=0x%x; position=0x%x; TLocDrvRequest Object=0x%x", (TInt) iDrive->iDriveNumber, (TUint) m.Length(), (TUint) m.Pos(), (TUint) &m );
}
m.CloseRemoteThread();
break;
}
case RLocalDrive::EControlCaps:
{
TBuf8<KMaxLocalDriveCapsLength> capsBuf;
capsBuf.SetMax();
capsBuf.FillZ();
m.Id()=ECaps;
m.RemoteDes()=(TAny*)capsBuf.Ptr(); // overload this
m.Length()=KMaxLocalDriveCapsLength; // for pinning
r=iDrive->Request(m);
if(r == KErrNone && iDrive->iMedia != NULL && iDrive->iMedia->iDriver != NULL)
{
// Fill in default media size if not specified by the driver
//
// - This uses the members of TLocalDriveCapsV4 which was primarily used
// to report NAND flash characteristics, but are general enough to be
// used to report the size of any type of media without adding yet
// another extension to TLocalDriveCapsVx.
//
TLocalDriveCapsV4& caps = *(TLocalDriveCapsV4*)capsBuf.Ptr();
if(caps.iSectorSizeInBytes == 0)
{
// Fill in a default value for the disk sector size
caps.iSectorSizeInBytes = 512;
// Zero the number of sectors, as a sector count makes no sense without a sector size
// - Fault in debug mode if a sector count is provided to ensure that media driver creators
// set this value,but in release mode continue gracefully be recalculating the sector count.
__ASSERT_DEBUG(caps.iNumberOfSectors == 0, LOCM_FAULT());
caps.iNumberOfSectors = 0;
caps.iNumPagesPerBlock = 1; // ...to ensure compatiility with NAND semantics
}
if(caps.iNumberOfSectors == 0)
{
const Int64 totalSizeInSectors = iDrive->iMedia->iDriver->TotalSizeInBytes() / caps.iSectorSizeInBytes;
__ASSERT_DEBUG(I64HIGH(totalSizeInSectors) == 0, LOCM_FAULT());
if(I64HIGH(totalSizeInSectors) == 0)
{
caps.iNumberOfSectors = I64LOW(totalSizeInSectors);
}
}
}
#if defined(OST_TRACE_COMPILER_IN_USE) && defined(_DEBUG)
const TLocalDriveCapsV5& caps=*(const TLocalDriveCapsV5*)capsBuf.Ptr();
#endif
OstTraceExt5( TRACE_INTERNALS, DLOCALDRIVE_REQUEST_CAPS1, "Device caps: iDriveNumber=%d; iSize=0x%x; iType=%d; iDriveAtt=%d; TLocDrvRequest Object=0x%x", (TInt)iDrive->iDriveNumber, (TUint) caps.iSize, (TInt) caps.iType, (TInt) caps.iDriveAtt, (TUint) &m);
OstTraceExt5( TRACE_INTERNALS, DLOCALDRIVE_REQUEST_CAPS2, "Device caps: iBaseAddress=0x%x; iFileSystemId=%d; iPartitionType=%d; iHiddenSectors=0x%x; iEraseBlockSize=0x%x", (TUint) caps.iBaseAddress, (TInt) caps.iFileSystemId, (TUint) caps.iPartitionType, (TUint) caps.iHiddenSectors, (TUint) caps.iEraseBlockSize);
#if defined(_DEBUG)
__KTRACE_OPT(KLOCDRV,DebugDumpDriveCaps(iDrive,capsBuf.Ptr()));
#endif
Kern::InfoCopy(*(TDes8*)a1, capsBuf);
break;
}
case RLocalDrive::EControlFormat:
{
m.Id()=EFormat;
r=m.ProcessMessageData(a1);
if (r==KErrNone)
{
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_FORMAT, "EFormat; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_FORMAT_RETURN, "EFormat Return; TLocDrvRequest Object=0x%x", (TUint) &m);
}
break;
}
case RLocalDrive::EControlEnlarge:
if ((TInt)a1<0)
{
r=KErrArgument;
break;
}
m.Length()=(TInt)a1;
m.Id()=EEnlarge;
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_ENLARGE, "EEnlarge; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_ENLARGE_RETURN, "EEnlarge Return; TLocDrvRequest Object=0x%x", (TUint) &m);
break;
case RLocalDrive::EControlReduce:
{
if ((TInt)a1<0 || (TInt)a2<0)
{
r=KErrArgument;
break;
}
m.Pos()=(TInt)a1;
m.Length()=(TInt)a2;
m.Id()=EReduce;
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_REDUCE, "EReduce; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_REDUCE_RETURN, "EReduce Return; TLocDrvRequest Object=0x%x", (TUint) &m);
break;
}
case RLocalDrive::EControlForceMediaChange:
m.Pos()=(TInt)a1;
m.Id()=EForceMediaChange;
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_FORCEMEDIACHANGE, "EForceMediaChange; TLocDrvRequest Object=0x%x", (TUint) &m);
r = iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_FORCEMEDIACHANGE_RETURN, "EForceMediaChange Return; TLocDrvRequest Object=0x%x", (TUint) &m);
break;
case RLocalDrive::EControlMediaDevice:
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLMEDIADEVICE, "EControlMediaDevice; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->iPrimaryMedia->iDevice;
break;
case RLocalDrive::EControlIsRemovable:
{
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLISREMOVABLE, "EControlIsRemovable; TLocDrvRequest Object=0x%x", (TUint) &m);
TInt sockNum;
r=iDrive->iPrimaryMedia->IsRemovableDevice(sockNum);
if (r)
kumemput32(a1,&sockNum,sizeof(TInt));
break;
}
case RLocalDrive::EControlControlIO:
{
TLocalDriveControlIOData d;
kumemget32(&d,a1,sizeof(d));
m.Id() = EControlIO;
m.iArg[0] = (TAny*) d.iCommand;
m.iArg[1] = d.iParam1;
m.iArg[2] = d.iParam2;
// if d.iHandle is == KLocalMessageHandle (-1),
// d.aParam1 and d.aParam2 are TAny* pointers
//
// if d.iHandle is == 0,
// d.aParam1 and d.aParam2 are TInts
//
// if d.iHandle is > 0,
// d.aParam1 is a data pointer (TUint8*)
// d.aParam2 is an optional extra paramater (TInt)
// d.iHandle is a data length (TInt)
m.iArg[3] = (TAny*) d.iHandle;
//We're highjacking fields representing
//length and position in a normal message, so
//let's not have the dispatcher function attempt
//to adjust for partition size.
m.Flags() |= TLocDrvRequest::EAdjusted;
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLCONTROLIO, "EControlControlIO; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLCONTROLIO_RETURN, "EControlControlIO Return; TLocDrvRequest Object=0x%x", (TUint) &m);
break;
}
case RLocalDrive::EControlSetMountInfo:
{
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLSETMOUNTINFO, "EControlSetMountInfo; TLocDrvRequest Object=0x%x", (TUint) &m);
m.Id()=ERead;
r=m.ProcessMessageData(a1);
DPrimaryMediaBase* pM=iDrive->iPrimaryMedia;
if(!pM || r!=KErrNone)
break;
if (pM->iMountInfo.iThread)
{
NKern::ThreadEnterCS();
//Close original thread
Kern::SafeClose((DObject*&) pM->iMountInfo.iThread,NULL);
if (m.RemoteDes()!=NULL)
{
//Set new mount info and leave setting thread open
#ifdef __DEMAND_PAGING__
// lock the mount info if this is a data paging media - and keep it locked
if ((DataPagingDfcQ(pM)) && ((r = LockMountInfo(*pM, m)) != KErrNone))
break;
#endif
pM->iMountInfo.iInfo=(TDesC8*)m.RemoteDes();
pM->iMountInfo.iThread=m.RemoteThread();
}
else
{
//Clear existing mount info and close setting thread
#ifdef __DEMAND_PAGING__
// unlock the mount info if this is a data paging media
UnlockMountInfo(*pM);
#endif
pM->iMountInfo.iInfo=NULL;
pM->iMountInfo.iThread=NULL;
m.CloseRemoteThread();
}
NKern::ThreadLeaveCS();
r=KErrNone;
}
else
{
//Setting mount info for the first time
if (m.RemoteDes()==NULL)
{
// if no mount info, close setting thread opened in ProcessMessageData()
m.CloseRemoteThread();
break;
}
NKern::ThreadEnterCS();
#ifdef __DEMAND_PAGING__
// lock the mount info if this is a data paging media - and keep it locked
if ((DataPagingDfcQ(pM)) && ((r = LockMountInfo(*pM, m)) != KErrNone))
break;
#endif
pM->iMountInfo.iInfo=(TDesC8*)m.RemoteDes();
pM->iMountInfo.iThread=m.RemoteThread();
NKern::ThreadLeaveCS();
r=KErrNone;
}
break;
}
case RLocalDrive::EControlPasswordLock:
{
m.Id()=EPasswordLock;
m.RemoteDes() = a1;
TMediaPassword oldPasswd;
TMediaPassword newPasswd;
TLocalDrivePasswordData pswData;
r = ReadPasswordData(m, pswData, oldPasswd, newPasswd);
if (r == KErrNone)
{
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDLOCK, "EPasswordLock; TLocDrvRequest Object=0x%x", (TUint) &m);
r = iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDLOCK_RETURN, "EPasswordLock Return; TLocDrvRequest Object=0x%x", (TUint) &m);
}
break;
}
case RLocalDrive::EControlPasswordUnlock:
{
m.Id()=EPasswordUnlock;
m.RemoteDes() = a1;
TMediaPassword oldPasswd;
TMediaPassword newPasswd;
TLocalDrivePasswordData pswData;
r = ReadPasswordData(m, pswData, oldPasswd, newPasswd);
if(r == KErrNone)
{
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDUNLOCK, "EPasswordUnLock; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDUNLOCK_RETURN, "EPasswordUnLock Return; TLocDrvRequest Object=0x%x", (TUint) &m);
}
if (r == KErrNone)
iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
break;
}
case RLocalDrive::EControlPasswordClear:
{
m.Id()=EPasswordClear;
m.RemoteDes() = a1;
TMediaPassword oldPasswd;
TMediaPassword newPasswd;
TLocalDrivePasswordData pswData;
r = ReadPasswordData(m, pswData, oldPasswd, newPasswd);
if (r == KErrNone)
{
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDCLEAR, "EPasswordClear; TLocDrvRequest Object=0x%x", (TUint) &m);
r = iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDCLEAR_RETURN, "EPasswordClear Return; TLocDrvRequest Object=0x%x", (TUint) &m);
}
break;
}
case RLocalDrive::EControlPasswordErase:
{
m.Id()=EPasswordErase;
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDERASE, "EPasswordErase; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDERASE_RETURN, "EPasswordErase Return; TLocDrvRequest Object=0x%x", (TUint) &m);
if(r == KErrNone)
iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
break;
}
case RLocalDrive::EControlNotifyChange:
if (iCleanup.iThread != &Kern::CurrentThread())
Kern::PanicCurrentThread(KLitLocMedia,KErrAccessDenied);
r=KErrNone;
if (!iNotifyChangeRequest->StatusPtr())
r = iNotifyChangeRequest->SetStatus((TRequestStatus*) a1);
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLNOTIFYCHANGE, "EControlNotifyChange; TLocDrvRequest Object=0x%x", (TUint) &m);
break;
case RLocalDrive::EControlNotifyChangeCancel:
if (iCleanup.iThread != &Kern::CurrentThread())
Kern::PanicCurrentThread(KLitLocMedia,KErrAccessDenied);
Kern::QueueRequestComplete(iCleanup.iThread,iNotifyChangeRequest,KErrCancel);
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLNOTIFYCHANGECANCEL, "EControlNotifyChangeCancel; TLocDrvRequest Object=0x%x", (TUint) &m);
break;
case RLocalDrive::EControlReadPasswordStore:
{
TUint8 passData[TPasswordStore::EMaxPasswordLength];
m.RemoteDes() = (TAny*) passData;
m.Length() = sizeof(passData);
m.Id()=EReadPasswordStore;
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_READPASSWORDSTORE, "EReadPasswordStore; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_READPASSWORDSTORE_RETURN, "EReadPasswordStore Return; TLocDrvRequest Object=0x%x", (TUint) &m);
if (r==KErrNone)
{
TPtr8 pData(passData, (TInt) m.Length(), TPasswordStore::EMaxPasswordLength);
m.RemoteDes()=(TDes8*)a1;
r = m.WriteRemote(&pData,0);
}
break;
}
case RLocalDrive::EControlWritePasswordStore:
{
TUint8 passData[TPasswordStore::EMaxPasswordLength];
TPtr8 pData(passData, TPasswordStore::EMaxPasswordLength);
DThread* pT=m.RemoteThread();
if (!pT)
pT=m.Client();
m.RemoteDes() = (TDes8*)a1;
r = Kern::ThreadGetDesLength(pT, m.RemoteDes());
if ( r > pData.MaxLength() )
r = KErrOverflow;
if ( r < KErrNone)
break;
r = m.ReadRemote(&pData,0);
if (r != KErrNone)
break;
m.RemoteDes() = (TAny*) pData.Ptr();
m.Length() = pData.Length();
m.Id()=EWritePasswordStore;
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_WRITEPASSWORDSTORE, "EWritePasswordStore; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_WRITEPASSWORDSTORE_RETURN, "EReadPasswordStore Return; TLocDrvRequest Object=0x%x", (TUint) &m);
if(r == KErrNone)
iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
break;
}
case RLocalDrive::EControlPasswordStoreLengthInBytes:
{
m.Id()=EPasswordStoreLengthInBytes;
TInt length;
m.RemoteDes() = (TAny*) &length;
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDSTORELENGTH, "EPasswordStoreLengthInBytes; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_PASSWORDSTORELENGTH_RETURN, "EPasswordStoreLengthInBytes Return; TLocDrvRequest Object=0x%x", (TUint) &m);
if (r == KErrNone)
{
m.RemoteDes()=a1;
r = m.WriteRemoteRaw(&length,sizeof(TInt));
}
break;
}
case RLocalDrive::EControlGetLastErrorInfo:
{
m.Id()=EGetLastErrorInfo;
m.iArg[0]=this;
TErrorInfoBuf errorInfoBuf;
errorInfoBuf.SetMax();
errorInfoBuf.FillZ();
m.RemoteDes()=(TAny*) errorInfoBuf.Ptr(); // overload this
m.Length() = errorInfoBuf.MaxLength();
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_GETLASTERRORINFO, "EGetLastErrorInfo; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLGETLASTERRORINFO_RETURN, "EControlGetLastErrorInfo Return; TLocDrvRequest Object=0x%x", (TUint) &m);
Kern::InfoCopy(*(TDes8*)a1, errorInfoBuf);
break;
}
case RLocalDrive::EControlDeleteNotify:
{
m.Id()=EDeleteNotify;
r=m.ProcessMessageData(a1);
if (r==KErrNone)
{
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_DELETENOTIFY, "EDeleteNotify; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_DELETENOTIFY_RETURN, "EDeleteNotify Return; TLocDrvRequest Object=0x%x", (TUint) &m);
}
break;
}
case RLocalDrive::EControlQueryDevice:
{
TBuf8<KMaxQueryDeviceLength> queryBuf;
queryBuf.SetMax();
queryBuf.FillZ();
m.Id() = EQueryDevice;
m.iArg[0] = a1; // RLocalDrive::TQueryDevice
m.RemoteDes() = (TAny*)queryBuf.Ptr(); // overload this
m.Length() = KMaxLocalDriveCapsLength; // for pinning
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_QUERYDEVICE, "EQueryDevice; TLocDrvRequest Object=0x%x", (TUint) &m);
r=iDrive->Request(m);
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_QUERYDEVICE_RETURN, "EQueryDevice Return; TLocDrvRequest Object=0x%x", (TUint) &m);
Kern::InfoCopy(*(TDes8*)a2, queryBuf);
break;
}
}
__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive::DoControl D:%d M:%08x ret %d",iDrive->iDriveNumber, iDrive->iMedia, r));
__TRACE_TIMING(4);
OstTraceFunctionExitExt( DLOCALDRIVE_REQUEST_EXIT, this, r );
return r;
}
TInt DLocalDrive::ReadPasswordData(TLocDrvRequest& aReq, TLocalDrivePasswordData& aPswData, TMediaPassword& aOldPasswd, TMediaPassword& aNewPasswd)
{
TLocalDrivePasswordData clientData;
TInt r = aReq.ReadRemoteRaw(&clientData, sizeof(TLocalDrivePasswordData));
DThread* pT = aReq.RemoteThread();
if (!pT)
pT = aReq.Client();
if (r == KErrNone)
r = Kern::ThreadDesRead(pT, clientData.iOldPasswd, aOldPasswd, 0 ,KChunkShiftBy0);
if (r == KErrNone)
r = Kern::ThreadDesRead(pT, clientData.iNewPasswd, aNewPasswd, 0 ,KChunkShiftBy0);
aPswData.iStorePasswd = clientData.iStorePasswd;
aPswData.iOldPasswd = &aOldPasswd;
aPswData.iNewPasswd = &aNewPasswd;
aReq.RemoteDes() = (TAny*) &aPswData;
aReq.Flags()|= TLocDrvRequest::EKernelBuffer;
return r;
}
#ifdef __DEMAND_PAGING__
TInt DLocalDrive::LockMountInfo(DPrimaryMediaBase& aPrimaryMedia, TLocDrvRequest& aReq)
{
OstTraceExt2(TRACE_FLOW, DLOCALDRIVE_LOCKMOUNTINFO_ENTRY, "> aPrimaryMedia=%x;aReq=%x", (TUint) &aPrimaryMedia, (TUint) &aReq );
DMediaPagingDevice* pagingDevice = aPrimaryMedia.iBody->iPagingDevice;
if (pagingDevice == NULL)
{
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT1, this, KErrNone );
return KErrNone;
}
__ASSERT_DEBUG(pagingDevice->iMountInfoDataLock == NULL, LOCM_FAULT());
__ASSERT_DEBUG(pagingDevice->iMountInfoDescHdrLock == NULL, LOCM_FAULT());
__ASSERT_DEBUG(pagingDevice->iMountInfoDescLenLock == NULL, LOCM_FAULT());
DThread* pT = aReq.RemoteThread();
if (!pT)
pT = &Kern::CurrentThread(); // e.g. when using TBusLocalDrive directly
TInt length = 0;
TInt maxLength = 0;
TUint8* desAddress = NULL;
TInt r = Kern::ThreadGetDesInfo(pT,aReq.RemoteDes(),length,maxLength,desAddress,EFalse); // get descriptor length, maxlength and desAddress
if (r != KErrNone)
{
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT2, this, r );
return r;
}
if (length == 0)
{
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT3, this, KErrNone );
return KErrNone;
}
static const TUint8 LengthLookup[16]={4,8,12,8,12,0,0,0,0,0,0,0,0,0,0,0};
TUint32 desHdr;
r = Kern::ThreadRawRead(pT, aReq.RemoteDes(), &desHdr, sizeof(desHdr));
if(r!=KErrNone)
{
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT4, this, r );
return r;
}
TInt desType = desHdr >>KShiftDesType8;
TInt desHdrLen = LengthLookup[desType];
if(!desHdrLen)
{
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT5, this, KErrBadDescriptor );
return KErrBadDescriptor;
}
pagingDevice->iMountInfoDataLock = ThePinObjectAllocator->AcquirePinObject();
pagingDevice->iMountInfoDescHdrLock = ThePinObjectAllocator->AcquirePinObject();
pagingDevice->iMountInfoDescLenLock = ThePinObjectAllocator->AcquirePinObject();
if (pagingDevice->iMountInfoDataLock == NULL ||
pagingDevice->iMountInfoDescHdrLock == NULL ||
pagingDevice->iMountInfoDescLenLock == NULL)
{
UnlockMountInfo(aPrimaryMedia); // tidy up
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT6, this, KErrNoMemory );
return KErrNoMemory;
}
// First pin the descriptor header
DPinObjectAllocator::SVirtualPinContainer* lock;
lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock;
r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) (TUint8*) aReq.RemoteDes(), desHdrLen, pT);
if (r != KErrNone)
{
UnlockMountInfo(aPrimaryMedia); // tidy up
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT7, this, KErrNoMemory );
return KErrNoMemory;
}
// For EBufCPtr-type descriptors, need to pin the extra length before the buffer (!)
lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock;
if (desType == EBufCPtr)
{
TLinAddr extraLenAddr = TLinAddr(desAddress) - aReq.RemoteDesOffset() - sizeof(TUint32);
r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) (TUint8*) extraLenAddr, sizeof(TUint32), pT);
if (r != KErrNone)
{
UnlockMountInfo(aPrimaryMedia); // tidy up
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT8, this, KErrNoMemory );
return KErrNoMemory;
}
}
// Now pin the descriptor contents
lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock;
r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) desAddress, length, pT);
if (r != KErrNone)
{
UnlockMountInfo(aPrimaryMedia); // tidy up
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT9, this, KErrNoMemory );
return KErrNoMemory;
}
OstTraceFunctionExitExt( DLOCALDRIVE_LOCKMOUNTINFO_EXIT10, this, KErrNone );
return KErrNone;
}
void DLocalDrive::UnlockMountInfo(DPrimaryMediaBase& aPrimaryMedia)
{
OstTrace1(TRACE_FLOW, DLOCALDRIVE_UNLOCKMOUNTINFO_ENTRY, "> DLocalDrive::UnlockMountInfo;aPrimaryMedia=%x", (TUint) &aPrimaryMedia);
DMediaPagingDevice* pagingDevice = aPrimaryMedia.iBody->iPagingDevice;
if (pagingDevice == NULL || pagingDevice->iMountInfoDataLock == NULL)
{
OstTraceFunctionExit1( DLOCALDRIVE_UNLOCKMOUNTINFO_EXIT1, this );
return;
}
if (pagingDevice->iMountInfoDataLock)
{
Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock)->iObject);
ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock);
pagingDevice->iMountInfoDataLock = NULL;
}
if (pagingDevice->iMountInfoDescHdrLock)
{
Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock)->iObject);
ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock);
pagingDevice->iMountInfoDescHdrLock = NULL;
}
if (pagingDevice->iMountInfoDescLenLock)
{
Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock)->iObject);
ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock);
pagingDevice->iMountInfoDescLenLock = NULL;
}
OstTraceFunctionExit1( DLOCALDRIVE_UNLOCKMOUNTINFO_EXIT2, this );
}
#endif // __DEMAND_PAGING__
void DLocalDrive::NotifyChange(DPrimaryMediaBase& aPrimaryMedia, TBool aMediaChange)
{
OstTraceExt2( TRACE_FLOW, DLOCALDRIVE_NOTIFYCHANGE_ENTRY, "> DLocalDrive::NotifyChange;aPrimaryMedia=%x;aMediaChange=%d", (TUint) &aPrimaryMedia, aMediaChange );
#ifndef __DEMAND_PAGING__
aPrimaryMedia;
#endif
// Complete any notification request on media change or power down
if (aMediaChange)
{
DThread* pC=NULL;
NKern::LockSystem();
if (iCleanup.iThread)
{
pC=iCleanup.iThread;
pC->Open();
}
NKern::UnlockSystem();
if (pC)
{
TBool b = ETrue;
// if change not yet queued, queue it now
if (iNotifyChangeRequest->IsReady())
{
*((TBool*) iNotifyChangeRequest->Buffer()) = b;
Kern::QueueRequestComplete(pC,iNotifyChangeRequest,KErrNone);
}
// If change has not even been requested by the client, maintain the pre-wdp behaviour
// and write data immediately back to client (possibly taking a page fault)
// N.B. Must NOT do this on data paging media
#ifdef __DEMAND_PAGING__
else if (!DataPagingDfcQ(&aPrimaryMedia))
#else
else
#endif
{
Kern::ThreadRawWrite(pC, iNotifyChangeRequest->DestPtr(), &b, sizeof(b), NULL);
}
pC->AsyncClose();
}
}
OstTraceFunctionExit1( DLOCALDRIVE_NOTIFYCHANGE_EXIT, this );
}
TLocalDriveCleanup::TLocalDriveCleanup()
{
}
// This will be called when the original client thread exits
// It is called in the context of the exiting thread with the system locked.
void TLocalDriveCleanup::Cleanup()
{
DLocalDrive& d=LocalDrive();
d.iNotifyChangeRequest=NULL;
DThread* pC=iThread;
Remove();
iThread=NULL;
NKern::UnlockSystem();
pC->Close(NULL); // balances Open() in DoCreate
NKern::LockSystem();
}
/********************************************
* Local drive request class
********************************************/
/**
Reads data from the descriptor specified in the request, from the requesting
thread's process.
This is used by the media driver to read data from a descriptor in the
requesting thread. The remote data is copied into the specified descriptor,
starting at the specified offset within that descriptor's data area.
@param aDes The target descriptor into which data from the remote thread
is to be put.
@param anOffset The offset within the target descriptor data area, where data
from the remote thread is to be put. Note that this parameter
may be useful when write operations to the media must be broken
up into smaller chunks than the length requested.
@return KErrNone,if successful, otherwise one of the other
system-wide error codes.
@see Kern::ThreadDesRead()
*/
EXPORT_C TInt TLocDrvRequest::ReadRemote(TDes8* aDes, TInt anOffset)
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_READREMOTE_ENTRY, this );
TInt r;
DThread* pT=RemoteThread();
if (!pT)
pT=Client();
#ifdef __DEMAND_PAGING__ // only if driver has its own thread, we don't support paging in MD which run in the context of their clients
if (Flags() & ETClientBuffer)
{
r = Kern::ThreadBufRead(pT, (TClientBuffer*) RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0);
OstTraceFunctionExitExt( TLOCDRVREQUEST_READREMOTE_EXIT1, this, r );
return r;
}
__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
#endif
r = Kern::ThreadDesRead(pT,RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0);
OstTraceFunctionExitExt( TLOCDRVREQUEST_READREMOTE_EXIT2, this, r );
return r;
}
/**
Reads data from an arbitrary descriptor in the requesting thread's process.
This is used by the media driver to read data from a descriptor in the
requesting thread.
NB This is NOT supported on datapaging media as there is no guarantee
that the remote descriptor won't be paged out. If this function is called and
data-paging is enabled the kernel will fault in debug mode and return
KErrNotSupported in release mode.
@param aSrc A pointer to the source descriptor in the requesting thread's
address space.
@param aDes The target descriptor into which data from the remote thread
is to be put.
@return KErrNone,if successful,
KErrNotSupported if data-paging is enabled
otherwise one of the other system-wide error codes.
@see Kern::ThreadDesRead()
*/
EXPORT_C TInt TLocDrvRequest::ReadRemote(const TAny* aSrc, TDes8* aDes)
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_READ_REMOTE_ENTRY, this );
if (Flags() & TLocDrvRequest::EKernelBuffer)
{
aDes->Copy(* (TDesC8*) aSrc);
return KErrNone;
}
TInt r;
DThread* pT=RemoteThread();
if (!pT)
pT=Client();
#ifdef __DEMAND_PAGING__
__ASSERT_DEBUG(!DataPagingDfcQ(Drive()->iPrimaryMedia), LOCM_FAULT());
if (DataPagingDfcQ(Drive()->iPrimaryMedia))
{
OstTraceFunctionExitExt( TLOCDRVREQUEST_READ_REMOTE_EXIT1, this, KErrNotSupported );
return KErrNotSupported;
}
#endif
r = Kern::ThreadDesRead(pT,aSrc,*aDes,0,KChunkShiftBy0);
OstTraceFunctionExitExt( TLOCDRVREQUEST_READ_REMOTE_EXIT2, this, r );
return r;
}
/**
Reads raw data from the requesting thread's process.
This is used by the media driver to read raw data from a location in requesting
thread's address space. The remote data is copied into the specified
buffer.
@param aDest A pointer to the buffer where the data is to be written.
@param aSize The number of bytes to read.
@return KErrNone,if successful, otherwise one of the other
system-wide error codes.
@see Kern::ThreadRawRead()
*/
EXPORT_C TInt TLocDrvRequest::ReadRemoteRaw(TAny* aDest, TInt aSize)
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_READREMOTERAW_ENTRY, this );
if (Flags() & TLocDrvRequest::EKernelBuffer)
{
(void)memcpy(aDest, (TAny*) RemoteDes(), aSize);
return KErrNone;
}
TInt r;
DThread* pT=RemoteThread();
if (!pT)
pT=Client();
#ifdef __DEMAND_PAGING__
__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
#endif
r = Kern::ThreadRawRead(pT,RemoteDes(),aDest,aSize);
OstTraceFunctionExitExt( TLOCDRVREQUEST_READREMOTERAW_EXIT, this, r );
return r;
}
/**
Writes data to a descriptor in the requesting thread's process.
This is used by the media driver to write data to a descriptor in the requesting
thread. Data is copied from the specified descriptor, starting at the specified
offset within that descriptor's data area.
@param aDes The source descriptor from which data is to be written to
the remote thread.
@param anOffset The offset within the source descriptor data area, from where data
is to be written to the remote thread. Note that this parameter
may be useful when read operations from the media must be broken
up into smaller chunks than the length requested.
@return KErrNone,if successful, otherwise one of the other
system-wide error codes.
@see Kern::ThreadDesWrite()
*/
EXPORT_C TInt TLocDrvRequest::WriteRemote(const TDesC8* aDes, TInt anOffset)
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_WRITEREMOTE_ENTRY, this );
TInt r;
DThread* pC=Client();
DThread* pT=RemoteThread();
if (!pT)
pT=pC;
#ifdef __DEMAND_PAGING__
if (Flags() & ETClientBuffer)
{
r = Kern::ThreadBufWrite(pT, (TClientBuffer*) RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0,pC);
OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITEREMOTE_EXIT1, this, r );
return r;
}
#endif
r = Kern::ThreadDesWrite(pT,RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0,pC);
OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITEREMOTE_EXIT2, this, r );
return r;
}
/**
Writes raw data to the requesting thread's process.
This is used by the media driver to write raw data to a location in the
requesting thread's address space.
@param aSrc The source addres from which data is to be written to
the remote thread.
@param aSize The number of bytes to write.
@return KErrNone,if successful, otherwise one of the other
system-wide error codes.
@see Kern::ThreadRawWrite()
*/
EXPORT_C TInt TLocDrvRequest::WriteRemoteRaw(const TAny* aSrc, TInt aSize)
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_WRITEREMOTERAW_ENTRY, this );
TInt r;
DThread* pC=Client();
DThread* pT=RemoteThread();
if (!pT)
pT=pC;
#ifdef __DEMAND_PAGING__
__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
#endif
r = Kern::ThreadRawWrite(pT,RemoteDes(),aSrc,aSize,pC);
OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITEREMOTERAW_EXIT, this, r );
return r;
}
TInt TLocDrvRequest::ProcessMessageData(TAny* aPtr)
//
// Get read/write parameters from client and open remote thread
//
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_PROCESSMESSAGEDATA_ENTRY, this );
RemoteThread()=NULL;
DThread& t=Kern::CurrentThread();
TLocalDriveMessageData d;
kumemget32(&d,aPtr,sizeof(d));
OstTrace1( TRACE_INTERNALS, TLOCDRVREQUEST_PROCESSMESSAGEDATA, "Message handle=%d", d.iHandle );
if (d.iHandle!=KLocalMessageHandle && Id()!=DLocalDrive::EFormat)
{
NKern::LockSystem();
DThread* pT = RMessageK::MessageK(d.iHandle)->iClient;
if (!pT || pT->Open()!=KErrNone)
{
NKern::UnlockSystem();
OstTraceFunctionExitExt( TLOCDRVREQUEST_PROCESSMESSAGEDATA_EXIT1, this, KErrBadHandle );
return KErrBadHandle;
}
t.iExtTempObj=pT;
RemoteThread()=pT;
NKern::UnlockSystem();
}
Pos()=d.iPos;
Length()=d.iLength;
RemoteDes()=(TAny*)d.iPtr;
RemoteDesOffset()=d.iOffset;
DriverFlags()=d.iFlags;
if (Pos()<0 || Length()<0)
{
OstTraceFunctionExitExt( TLOCDRVREQUEST_PROCESSMESSAGEDATA_EXIT2, this, KErrArgument );
return KErrArgument;
}
OstTraceFunctionExitExt( TLOCDRVREQUEST_PROCESSMESSAGEDATA_EXIT3, this, KErrNone );
return KErrNone;
}
void TLocDrvRequest::CloseRemoteThread()
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_CLOSEREMOTETHREAD_ENTRY, this );
if (!RemoteThread())
{
OstTraceFunctionExit1( TLOCDRVREQUEST_CLOSEREMOTETHREAD_EXIT1, this );
return;
}
NKern::ThreadEnterCS();
DThread& t=Kern::CurrentThread();
RemoteThread()=NULL;
Kern::SafeClose((DObject*&)t.iExtTempObj,NULL);
NKern::ThreadLeaveCS();
OstTraceFunctionExit1( TLOCDRVREQUEST_CLOSEREMOTETHREAD_EXIT2, this );
}
EXPORT_C TInt TLocDrvRequest::CheckAndAdjustForPartition()
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION_ENTRY, this );
TLocDrv& d=*Drive();
__KTRACE_OPT(KLOCDRV,Kern::Printf("CheckAndAdjustForPartition drive %d partition len %lx",d.iDriveNumber,d.iPartitionLen));
OstTraceExt2( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION1, "iDriveNumber=%d; partition length=0x%lx", d.iDriveNumber, (TInt) d.iPartitionLen );
Flags() |= EAdjusted;
TInt r;
switch (Id())
{
case DLocalDrive::ECaps:
case DLocalDrive::EForceMediaChange:
case DLocalDrive::EPasswordLock:
case DLocalDrive::EPasswordUnlock:
case DLocalDrive::EPasswordClear:
case DLocalDrive::EPasswordErase:
case DLocalDrive::EReadPasswordStore:
case DLocalDrive::EWritePasswordStore:
case DLocalDrive::EPasswordStoreLengthInBytes:
case DLocalDrive::EQueryDevice:
{
r = KErrNone;
break;
}
case DLocalDrive::EEnlarge:
__KTRACE_OPT(KLOCDRV,Kern::Printf("Enlarge request %lx",Length()));
OstTrace1( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION2, "Enlarge request=0x%lx", Length() );
if (Length()>KMaxTInt)
r = KErrArgument;
else
r = KErrNone;
break;
case DLocalDrive::EReduce:
__KTRACE_OPT(KLOCDRV,Kern::Printf("Reduce request %lx@%lx",Length(),Pos()));
OstTraceExt2( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION3, "Reduce request length=0x%lx; position=0x%lx", (TUint) Length(), (TUint) Pos() );
if (Pos()+Length()>d.iPartitionLen)
r = KErrArgument;
else
r = KErrNone;
break;
case DLocalDrive::EFormat:
__KTRACE_OPT(KLOCDRV,Kern::Printf("Format request %lx@%lx",Length(),Pos()));
OstTraceExt2( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION4, "Format request length=0x%lx; position=0x%lx", (TUint) Length(), (TUint) Pos() );
if (!(DriverFlags() & RLocalDrive::ELocDrvWholeMedia))
{
if (Pos()>d.iPartitionLen)
{
Length()=0;
r = KErrEof;
break;
}
Int64 left=d.iPartitionLen-Pos();
if (left<Length())
Length()=left;
Pos()+=d.iPartitionBaseAddr;
if (Length()==0)
{
r = KErrEof;
break;
}
}
r = KErrNone;
break;
#ifdef __DEMAND_PAGING__
case DMediaPagingDevice::ERomPageInRequest:
// if the ROM was reported to LOCM then it will also need to be adjusted....
// Otherwise the media driver adjust it internally
case DMediaPagingDevice::ECodePageInRequest:
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Adjusted Paging read request %lx@%lx",Length(),Pos()));
OstTraceDefExt2(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, TLOCDRVREQUESTCHECKANDADJUSTFORPARTITION5, "Adjusted Paging read request length=0x%lx; position=0x%lx", (TUint) Length(), (TUint) Pos());
if (Pos()+Length()>d.iPartitionLen)
{
r = KErrArgument;
break;
}
Pos()+=d.iPartitionBaseAddr;
r = KErrNone;
break;
#endif
default: // read or write or fragment
__KTRACE_OPT(KLOCDRV,Kern::Printf("R/W request %lx@%lx",Length(),Pos()));
OstTraceExt2( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION6, "Read/Write request length=0x%x; position=0x%x", (TUint) Length(), (TUint) Pos() );
if (DriverFlags() & RLocalDrive::ELocDrvWholeMedia)
{
if (d.iMedia && d.iMedia->iDriver && Pos()+Length() > d.iMedia->iDriver->iTotalSizeInBytes)
{
r = KErrArgument;
break;
}
}
else
{
if (Pos()+Length() > d.iPartitionLen)
{
r = KErrArgument;
break;
}
Pos()+=d.iPartitionBaseAddr;
}
r = KErrNone;
}
OstTraceFunctionExitExt( TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION_EXIT, this, r );
return r;
}
/********************************************
* Local drive class
********************************************/
TLocDrv::TLocDrv(TInt aDriveNumber)
{
OstTraceFunctionEntryExt( TLOCDRV_TLOCDRV_ENTRY, this );
memclr(this, sizeof(TLocDrv));
iDriveNumber=aDriveNumber;
iPartitionNumber=-1;
OstTraceFunctionExit1( TLOCDRV_TLOCDRV_EXIT, this );
}
/**
Initialises the DMedia entity with the media device number and ID.
@param aDevice The unique ID for this device. This can take one of the
enumerated values defined in TMediaDevice enum.
@param aMediaId The unique ID to associate with this media entity.
@return KErrNone,if successful, otherwise one of the other
system-wide error codes.
@see TMediaDevice
*/
EXPORT_C TInt DMedia::Create(TMediaDevice aDevice, TInt aMediaId, TInt)
{
OstTraceFunctionEntry1( DMEDIA_CREATE_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DMedia::Create media %d device %d",aMediaId,aDevice));
OstTraceExt2(TRACE_INTERNALS, DMEDIA_CREATE, "media=%d; device=%d", aMediaId, (TUint) aDevice);
iMediaId=aMediaId;
iDevice=aDevice;
OstTraceFunctionExitExt( DMEDIA_CREATE_EXIT, this, KErrNone );
return KErrNone;
}
/********************************************
* Primary Media Class
********************************************/
void asyncDfc(TAny* aPtr)
{
OstTraceFunctionEntry0( _ASYNCDFC_ENTRY );
DPrimaryMediaBase* pM=(DPrimaryMediaBase*)aPtr;
if (pM->iState==DMedia::EOpening)
pM->DoOpenMediaDriverComplete(pM->iAsyncErrorCode);
else if (pM->iState==DMedia::EReadPartitionInfo)
pM->DoPartitionInfoComplete(pM->iAsyncErrorCode);
OstTraceFunctionExit0( _ASYNCDFC_EXIT );
}
void handleMsg(TAny* aPtr)
{
OstTraceFunctionEntry0( _HANDLEMSG_ENTRY );
DPrimaryMediaBase* primaryMedia=(DPrimaryMediaBase*)aPtr;
for(TLocDrvRequest* m = (TLocDrvRequest*) primaryMedia->iMsgQ.iMessage;
m != NULL;
m = (TLocDrvRequest*) primaryMedia->iMsgQ.Poll())
{
#if defined(_DEBUG)
if (!primaryMedia->iMsgQ.iQ.IsEmpty())
__KTRACE_OPT(KLOCDRV, Kern::Printf("TRACE: handleMsg, queue not empty %08X", m));
#endif
primaryMedia->HandleMsg(*m);
#ifdef __DEMAND_PAGING__
// don't empty the queue if this media is paging as there
// may be a (higher-priority) paging DFC waiting to run...
if (primaryMedia->iPagingMedia)
break;
#endif
}
primaryMedia->iMsgQ.Receive(); // allow reception of more messages
OstTraceFunctionExit0( _HANDLEMSG_EXIT );
}
EXPORT_C DPrimaryMediaBase::DPrimaryMediaBase()
: iMsgQ(handleMsg, this, NULL, 1),
iDeferred(NULL, NULL, NULL, 0), // callback never used
iWaitMedChg(NULL, NULL, NULL, 0), // callback never used
iAsyncDfc(asyncDfc, this, 1)
/**
Constructor of DPrimaryMediaBase class.
Initialises the media state as closed.
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_DPRIMARYMEDIABASE_ENTRY, this );
iState = EClosed;
}
EXPORT_C TInt DPrimaryMediaBase::Create(TMediaDevice aDevice, TInt aMediaId, TInt aLastMediaId)
/**
Called from LocDrv::RegisterMediaDevice() function.
Calls DMedia::Create()
@param aDevice Local media ID
@param aMediaId Media Id (unique for a media subsystem)
@param aLastMediaId This indicates number of used media ids+ number of DMedia objects to be associated with the media driver.
@return KErrNone
@see TMediaDevice
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_CREATE_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase::Create media %d-%d device %d",aMediaId,aLastMediaId,aDevice));
OstTraceExt3( TRACE_INTERNALS, DPRIMARYMEDIABASE_CREATE, "aMediaId=%d; aLastMediaId=%d; aDevice=%d ", aMediaId, aLastMediaId, (TUint) aDevice );
TInt r=DMedia::Create(aDevice,aMediaId,0);
if (r != KErrNone)
{
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_CREATE_EXIT1, this, r );
return r;
}
iBody = new DBody;
if (iBody == NULL)
{
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_CREATE_EXIT2, this, KErrNoMemory );
return KErrNoMemory;
}
#ifdef __DEMAND_PAGING__
TInt pageSize = Kern::RoundToPageSize(1);
iBody->iPageSizeMsk = pageSize-1;
#endif
iLastMediaId=aLastMediaId;
if (r==KErrNone && iDfcQ)
{
iMsgQ.SetDfcQ(iDfcQ);
iDeferred.SetDfcQ(iDfcQ);
iWaitMedChg.SetDfcQ(iDfcQ);
iAsyncDfc.SetDfcQ(iDfcQ);
}
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_CREATE_EXIT3, this, KErrNone );
return KErrNone;
}
EXPORT_C TInt DPrimaryMediaBase::Connect(DLocalDrive* aLocalDrive)
/**
Connects to a local drive
@param aLocalDrive Local drive logical channel abstraction
@pre Kernel must be unlocked
@pre Current thread in critical section
@post Kernel must be unlocked
@return KErrNone, if successful
KErrNotFound, If no PDD matches criteria while getting driver list
KErrNoMemory, If the array could not be expanded at some point while getting driver list or ran out of memory while opening media driver
KErrNotReady, If not ready when trying to open media driver
otherwise, one of the other system wide error codes.
@see DLocalDrive
*/
{
OstTraceFunctionEntryExt( DPRIMARYMEDIABASE_CONNECT_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Connect %O",iMediaId,aLocalDrive));
OstTraceExt2( TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_CONNECT, "iMediaId=%d; iDriveNumber=%d", iMediaId, aLocalDrive->iDrive->iDriveNumber );
TInt r=KErrNone;
if (iDfcQ)
{
TThreadMessage& m=Kern::Message();
m.iValue=EConnect;
m.iArg[0]=aLocalDrive;
r=m.SendReceive(&iMsgQ);
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_CONNECT_EXIT1, this, r );
return r;
}
// If no DFC queue, must be a fixed media device
// If this is the first connection, open media driver now
// Assume no non-primary media exist on this device
NKern::LockSystem();
TBool first=iConnectionQ.IsEmpty();
iConnectionQ.Add(&aLocalDrive->iLink);
NKern::UnlockSystem();
if (first)
{
r=OpenMediaDriver();
if (r!=KErrNone)
{
NKern::LockSystem();
aLocalDrive->Deque();
NKern::UnlockSystem();
}
}
if (r==KErrNone)
aLocalDrive->iDrive->iMedia=this;
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_CONNECT_EXIT2, this, r );
return r;
}
EXPORT_C void DPrimaryMediaBase::Disconnect(DLocalDrive* aLocalDrive)
/**
Disconnects from a local drive
@param aLocalDrive Local drive logical channel abstraction
@pre Kernel must be unlocked
@pre Current thread in critical section
@post Kernel must be unlocked
@see DLocalDrive
*/
{
OstTraceFunctionEntryExt( DPRIMARYMEDIABASE_DISCONNECT_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Disconnect %O",iMediaId,aLocalDrive));
OstTraceExt2( TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_DISCONNECT, "iMediaId=%d; iDriveNumber=%d", iMediaId, aLocalDrive->iDrive->iDriveNumber );
if (iDfcQ)
{
TThreadMessage& m=Kern::Message();
m.iValue=EDisconnect;
m.iArg[0]=aLocalDrive;
m.SendReceive(&iMsgQ);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DISCONNECT_EXIT1, this );
return;
}
// If no DFC queue, must be a fixed media device
// If this is the last connection, close media driver now
// Assume no non-primary media exist on this device
DMediaDriver* pD=NULL;
NKern::LockSystem();
aLocalDrive->iDrive->iMedia=NULL;
aLocalDrive->Deque();
if (iConnectionQ.IsEmpty())
{
pD=iDriver;
iDriver=NULL;
}
NKern::UnlockSystem();
if (pD)
pD->Close();
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DISCONNECT_EXIT2, this );
}
EXPORT_C TInt DPrimaryMediaBase::Request(TLocDrvRequest& aReq)
/**
Issues a local drive request. It is called from TLocDrv::Request() function .
Each local drive request is encapsulated as a TLocDrvRequest- a class derived from TThreadMessage, the kernel message class.
TLocDrvRequest contains information pertaining to the request, including the ID and any associated parameters such as drive position, length and source/destination location.
Passes the request through to the media driver.
@param m Encapsulates the request information received from the client
@pre Enter with kernel unlocked
@post Leave with Kernel unlocked
@return KErrNone,if successful
KErrBadDescriptor, if request encapsulates a bad descriptor
Otherwise, one of the other system wide error codes.
@see TLocDrvRequest
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_REQUEST_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Request(%08x)",iMediaId,&aReq));
__KTRACE_OPT(KLOCDRV,Kern::Printf("this=%x, ReqId=%d, Pos=%lx, Len=%lx, remote thread %O",this,aReq.Id(),aReq.Pos(),aReq.Length(),aReq.RemoteThread()));
OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DPRIMARYMEDIABASE_REQUEST, "reqId=%d; length=0x%lx; position=0x%lx; remote thread=0x%x", (TInt) aReq.Id(), (TUint) aReq.Length(), (TUint) aReq.Pos(), (TUint) aReq.RemoteThread());
TInt reqId = aReq.Id();
if (reqId == DLocalDrive::ECaps)
DefaultDriveCaps(*(TLocalDriveCapsV2*)aReq.RemoteDes()); // fill in stuff we know even if no media present
TInt r = QuickCheckStatus();
if (r != KErrNone && aReq.Id()!=DLocalDrive::EForceMediaChange && // EForceMediaChange, and
aReq.Id()!=DLocalDrive::EReadPasswordStore && // Password store operations
aReq.Id()!=DLocalDrive::EWritePasswordStore && // do not require the media
aReq.Id()!=DLocalDrive::EPasswordStoreLengthInBytes) // to be ready.)
{
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_REQUEST_EXIT, this, r );
return r;
}
// for ERead & EWrite requests, get the linear address for pinning & DMA
TUint8* linAddress = NULL;
TClientBuffer clientBuffer;
DThread* pT = NULL;
if (reqId == DLocalDrive::ERead || reqId == DLocalDrive::EWrite)
{
pT = aReq.RemoteThread();
if (!pT)
pT = &Kern::CurrentThread(); // e.g. when using TBusLocalDrive directly
// for silly zero-length requests, return immediately, setting the client
// descriptor length to zero if it's a read request
if (aReq.Length() == 0)
{
DThread* pC = &Kern::CurrentThread();
r = KErrNone;
if (reqId == DLocalDrive::ERead)
{
TPtrC8 ptr(NULL, 0);
r = Kern::ThreadDesWrite(pT, aReq.RemoteDes(), ptr, aReq.RemoteDesOffset(), KChunkShiftBy0,pC);
}
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_REQUEST_EXIT2, this, r );
return r;
}
clientBuffer.SetFromDescriptor(aReq.RemoteDes(), pT);
TInt length = 0;
TInt maxLength = 0;
TInt r = Kern::ThreadGetDesInfo(pT,aReq.RemoteDes(),length,maxLength,linAddress,EFalse); // get descriptor length, maxlength and linAddress
if (r != KErrNone)
{
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_REQUEST_EXIT3, this, r );
return r;
}
linAddress+= aReq.RemoteDesOffset();
#ifdef __DEMAND_PAGING__
// NB change in behavior IF DATA PAGING IS ENABLED: TLocDrvRequest::RemoteDes() points
// to a TClientBuffer rather than the client's remote descriptor
if (DataPagingDeviceRegistered)
{
aReq.RemoteDes() = &clientBuffer;
aReq.Flags() |= TLocDrvRequest::ETClientBuffer;
}
#endif
}
if (iDfcQ)
{
__TRACE_TIMING(0x10);
#ifdef __DEMAND_PAGING__
// If this is a ROM/Code paging media, pin writes
// If there is a Data paging media registered, pin all requests with descriptors
if ( (DataPagingDeviceRegistered) || (reqId == DLocalDrive::EWrite && RomPagingDfcQ(this)) )
{
r = PinSendReceive(aReq, (TLinAddr) linAddress);
}
else
#endif // __DEMAND_PAGING__
r = SendReceive(aReq, (TLinAddr) linAddress);
}
else
{
// If no DFC queue, must be a fixed media device
// Media driver must already have been opened
// Assume no non-primary media exist on this device
// Just pass request straight through to media driver
r = aReq.CheckAndAdjustForPartition();
if (r == KErrNone)
r = iDriver->Request(aReq);
}
#ifdef __DEMAND_PAGING__
// NB change in behavior IF DATA PAGING IS ENABLED: TLocDrvRequest::RemoteDes() points
// to a TClientBuffer rather than the client's remote descriptor
if (reqId == DLocalDrive::ERead && DataPagingDeviceRegistered && r == KErrNone)
{
r = clientBuffer.UpdateDescriptorLength(pT);
}
#endif
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_REQUEST_EXIT4, this, r );
return r;
}
#ifdef __DEMAND_PAGING__
TInt DPrimaryMediaBase::PinSendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress)
{
OstTraceExt2(TRACE_FLOW, DPRIMARYMEDIABASE_PINSENDRECEIVE_ENTRY, "> DPrimaryMediaBase::PinSendReceive;aReq=%x;aLinAddress=%x;", (TUint) &aReq, (TUint) &aLinAddress );
__ASSERT_DEBUG(ThePinObjectAllocator, LOCM_FAULT());
TInt msgId = aReq.Id();
TInt r;
switch(msgId)
{
case DLocalDrive::EControlIO:
{
TInt controlIoType = aReq.Int3();
switch(controlIoType)
{
case KLocalMessageHandle:
// ControlIo is not supported if either of the two bare (TAny*) pointers are non-NULL
// as it's not possible to determine what the pointers are pointing at...
if (aReq.Int1() || aReq.Int2())
{
__KTRACE_OPT(KDATAPAGEWARN, Kern::Printf("Data paging: Naked EControlIO not supported on paging device: fn=%x", aReq.Int0()));
r = KErrNotSupported;
break;
}
// fall into...
case 0:
r = SendReceive(aReq);
break;
default:
// if Int3() is > 0, Int1() is a data pointer, and Int3() is a length
if (controlIoType > (TInt) ThePinObjectAllocator->iFragmentGranularity)
{
r = KErrTooBig;
break;
}
if (controlIoType < 0)
{
r = KErrArgument;
break;
}
r = PinFragmentSendReceive(aReq, (TLinAddr) aReq.Ptr1(), controlIoType);
break;
}
break;
}
case DLocalDrive::ERead:
case DLocalDrive::EWrite:
{
r = PinFragmentSendReceive(aReq, aLinAddress, aReq.Length());
break;
}
// For all these requests, aReq.RemoteDes() points to a buffer on the stack in DLocalDrive::Request()
// This is a kernel stack & so should be unpaged & not require pinning...
case DLocalDrive::ECaps:
case DLocalDrive::EGetLastErrorInfo:
case DLocalDrive::EQueryDevice:
case DLocalDrive::EPasswordLock:
case DLocalDrive::EPasswordUnlock:
case DLocalDrive::EPasswordClear:
case DLocalDrive::EReadPasswordStore:
case DLocalDrive::EWritePasswordStore:
case DLocalDrive::EPasswordStoreLengthInBytes:
case DLocalDrive::EPasswordErase:
default:
r = SendReceive(aReq);
}
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_PINSENDRECEIVE_EXIT, this, r );
return r;
}
TInt DPrimaryMediaBase::PinFragmentSendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress, TInt aLength)
{
OstTraceExt3(TRACE_FLOW, DPRIMARYMEDIABASE_PINFRAGMENTSENDRECEIVE_ENTRY, "> DPrimaryMediaBase::PinFragmentSendReceive;aReq=%x;aLinAddress=%x;aLength=%d;", (TUint) &aReq, (TUint) &aLinAddress, aLength );
TLocDrvRequest fragment = aReq; // create a request on the stack for use during fragmentation, pre-fill with the original req args, leave original Kernel message as repository (thread will block, message contents won't change)
TInt r = KErrNone;
// Kern::Printf(">PFSR %02X aReq %08X aLinAddress %08X aLen %08X offset %08X", aReq.Id(), &aReq, aLinAddress, aLength, aReq.RemoteDesOffset());
DThread* pT = aReq.RemoteThread();
if (!pT)
pT=&Kern::CurrentThread(); // e.g. when using TBusLocalDrive directly
__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Fragmenting Read/Write Request(0x%08x) on drive(%d), remote des(0x%x), offset into des(0x%x), original req Length(0x%x)",&aReq,aReq.Drive()->iDriveNumber,(TInt)(aReq.RemoteDes()),aReq.RemoteDesOffset(),aLength));
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Remote thread(0x%08x), current thread(0x%08x), start of data to write(0x%08x)",aReq.RemoteThread(),&Kern::CurrentThread(),(TInt)aLinAddress));
OstTraceDefExt5(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_PINFRAGMENTSENDRECEIVE1, "Fragmenting Read/Write Request=0x%08x; drive=%d; remote des=0x%x; offset into des=0x%x; original length=0x%x", (TUint) &aReq, (TUint) aReq.Drive()->iDriveNumber, (TInt) (aReq.RemoteDes()), (TInt) aReq.RemoteDesOffset(), (TInt) aLength );
OstTraceDefExt3(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_PINFRAGMENTSENDRECEIVE2, "Remote Thread=0x%08x; current Thread=0x%x; start of data to write=0x%08x", (TUint) aReq.RemoteThread(), (TUint) &Kern::CurrentThread(),(TUint)aLinAddress );
// don't want this thread to be terminated until last fragment is sent to MD and mem can be free'd up
NKern::ThreadEnterCS();
__ASSERT_DEBUG(ThePinObjectAllocator, LOCM_FAULT());
TUint fragmentGranularity = ThePinObjectAllocator->iFragmentGranularity;
TInt dataLockResult = 0;
// fragmentation only allowed for read/write requests
__ASSERT_DEBUG(aLength <= (TInt) fragmentGranularity || (aReq.Id() == DLocalDrive::EWrite || aReq.Id() == DLocalDrive::ERead), LOCM_FAULT());
// Pin the client buffer
TInt pinnedLen;
for (TInt pos = 0; pos < aLength; pos+= pinnedLen, aLinAddress+= pinnedLen)
{
pinnedLen = 0;
// pin memory
TInt remainingLen = aLength - pos; // remaining length
// first attempt to pin memory with no pre-allocated buffers (which may fail)
DPinObjectAllocator::SVirtualPinContainer* pinDataObject = ThePinObjectAllocator->AcquirePinObject();
if (pinDataObject)
{
TInt lenToPin = Min(KMaxPinData, remainingLen);
TInt r = Kern::PinVirtualMemory(pinDataObject->iObject, aLinAddress, lenToPin, pT);
if (r == KErrNone)
{
pinnedLen = lenToPin;
}
else
{
#ifdef __DEBUG_DEMAND_PAGING__
Kern::Printf("Kern::PinVirtualMemory() error %d", r);
#endif
// pin failed, so use preallocated buffer instead
ThePinObjectAllocator->ReleasePinObject(pinDataObject);
pinDataObject = NULL;
}
}
if (!pinDataObject)
{
ThePinObjectAllocator->PreAllocatedDataLock().LockFragmentation();
TLinAddr start = aLinAddress;
do
{
TInt lenToPin = Min((TInt) fragmentGranularity, remainingLen - pinnedLen);
#ifdef __DEBUG_DEMAND_PAGING__
Kern::Printf(">SR PinS Id %d aLinAddress %08X lenToPin %08X offset %08X", aReq.Id(), aLinAddress, lenToPin);
#endif
dataLockResult = ThePinObjectAllocator->PreAllocatedDataLock().Lock(pT, start, lenToPin);
#ifdef __DEBUG_DEMAND_PAGING__
Kern::Printf("<SR PinS Id %d aLinAddress %08X lenToPin %08X offset %08X r %d", aReq.Id(), aLinAddress, lenToPin, r);
#endif
start+= lenToPin;
pinnedLen+= lenToPin;
}
while (dataLockResult == 0 && pinnedLen < remainingLen);
// if nothing pinned (dataLockResult == 0) or error (dataLockResult <0), release the mutex,
// otherwise (dataLockResult > 0) release it after calling SendReceive()
if (dataLockResult <= 0)
ThePinObjectAllocator->PreAllocatedDataLock().UnlockFragmentation();
#ifdef __DEBUG_DEMAND_PAGING__
if (dataLockResult < 0)
Kern::Printf("DFragmentationPagingLock::Lock() %d", dataLockResult);
#endif
if (dataLockResult < 0) // if lock returned an error then give up
{
r = dataLockResult;
break;
}
}
// fragment request Id defaults to same as original request
fragment.Id() = aReq.Id();
fragment.Length() = Int64(pinnedLen);
fragment.RemoteDesOffset() = aReq.RemoteDesOffset() + pos;
fragment.Pos() = aReq.Pos() + pos;
fragment.Flags() = aReq.Flags();
__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Send fragment (0x%08x) type(%d), length(0x%x), offset within original req(0x%x), pos in media(0x%lx)",&fragment,fragment.Id(), pinnedLen, pos, fragment.Pos()));
OstTraceDefExt5(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_PINFRAGMENTSENDRECEIVE3, "Send fragment 0x%08x; type=%d; length=0x%x; offset within original req=0x%x; position in media=0x%lx", (TUint) &fragment, (TInt) fragment.Id(), (TUint) pinnedLen, (TUint) pos, (TUint) fragment.Pos());
#ifdef BTRACE_PAGING_MEDIA
TInt buf[4];
buf[0] = pinnedLen; // fragment length
buf[1] = pos; // offset within original request
buf[2] = fragment.Pos(); // offset in media
buf[3] = (TInt)&pT->iNThread; // thread that issued the original write req
BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedFragmentBegin,&fragment,fragment.Id(),buf,sizeof(buf));
#endif
r = SendReceive(fragment, aLinAddress); // only come back here when message (fragment) has been completed
// unpin memory
if (pinDataObject)
{
Kern::UnpinVirtualMemory(pinDataObject->iObject);
ThePinObjectAllocator->ReleasePinObject(pinDataObject);
}
else if (dataLockResult > 0) // pinDataObject = NULL
{
__ASSERT_DEBUG(dataLockResult == 1, LOCM_FAULT());
ThePinObjectAllocator->PreAllocatedDataLock().Unlock();
ThePinObjectAllocator->PreAllocatedDataLock().UnlockFragmentation();
}
#ifdef BTRACE_PAGING_MEDIA
BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedFragmentEnd,&fragment,r);
#endif
if (r != KErrNone)
break;
}
NKern::ThreadLeaveCS();
// Kern::Printf("<PFSR %02X aReq %08X aLinAddress %08X aLen %08X offset %08X", aReq.Id(), &aReq, aLinAddress, aLength, aReq.RemoteDesOffset());
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_PINFRAGMENTSENDRECEIVE_EXIT, this, r );
return r;
}
#endif // __DEMAND_PAGING__
TInt DPrimaryMediaBase::SendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress)
/**
* If a Physical memory helper object is present for given drive,
* then message is routed via helper;
*
* @return KErrNone, if successful;
* otherwise, one of the other system wide error codes.
*
* @see TLocDrvRequest::SendReceive()
* @see DDmaHelper::SendReceive()
*/
{
OstTraceExt2( TRACE_FLOW, DPRIMARYMEDIABASE_SENDRECEIVE_ENTRY, "> DPrimaryMediaBase::SendReceive;aReq=%x;aLinAddress=%x", (TUint) &aReq, (TUint) &aLinAddress );
DDmaHelper* dmaHelper = aReq.Drive()->iDmaHelper;
#ifdef __DEMAND_PAGING__
RequestCountInc();
#endif
TInt r;
if (dmaHelper)
r = dmaHelper->SendReceive(aReq, aLinAddress);
else
{
r = aReq.SendReceive(&iMsgQ);
}
#ifdef __DEMAND_PAGING__
RequestCountDec();
#endif
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_SENDRECEIVE_EXIT, this, r );
return r;
}
EXPORT_C TInt DPrimaryMediaBase::ForceMediaChange(TInt)
/**
Forces a media change.The method can be overridden in the derived classes.
@param mode Media change mode
@return KErrNotSupported, in the default implementation
KErrNone, if successful
Otherwise, one of the other system wide error codes.
*/
{
// default implementation
return KErrNotSupported;
}
EXPORT_C TInt DPrimaryMediaBase::InitiatePowerUp()
/**
Initiates Power up sequence
@return KErrCompletion, operation is complete successfully or otherwise
KErrNone, if successful
Otherwise, one of the other system wide error codes.
*/
{
// default implementation, this is the default implementation.
return KErrCompletion;
}
EXPORT_C TInt DPrimaryMediaBase::QuickCheckStatus()
/**
Checks the status of the media device, whether the device is present,absent,not ready,etc.
The function can be overridden in the derived classes
@return KErrNone, if successful
Otherwise, one of the other system wide error codes.
*/
{
// default implementation
return KErrNone;
}
EXPORT_C void DPrimaryMediaBase::DefaultDriveCaps(TLocalDriveCapsV2& aCaps)
/**
Fills in the default drive capabilities in TLocalDriveCapsV2 .
It initializes media type of drive as unknown and has to be overridden in the derived class. Called from the Request ( ) function of the same class.
@param aCaps Media drive capability fields. Extension to Capabilities fields(i.e) in addition to TLocalDriveCaps mainly to support Nor flash
@see TLocalDriveCapsV2
*/
{
// default implementation
// aCaps is zeroed beforehand
aCaps.iType = EMediaUnknown;
}
EXPORT_C TBool DPrimaryMediaBase::IsRemovableDevice(TInt& /*aSocketNum*/)
/**
Checks whether it is a removable device or not
@param aSocketNum Socket number
@return ETrue=Removable Device
EFalse=Non-Removable device, default implementation
*/
{
// default implementation
return(EFalse);
}
EXPORT_C void DPrimaryMediaBase::HandleMsg(TLocDrvRequest& m)
/**
It handles the drive request encapsulated in TLocDrvRequest depending on the message id.
@param aRequest Encapsulates the request information received from the client
@see TLocDrvRequest
*/
{
OstTrace1( TRACE_FLOW, DPRIMARYMEDIABASE_HANDLEMSG_ENTRY, "> DPrimaryMediaBase::HandleMsg;m=%x;", (TUint) &m);
switch (m.iValue)
{
case EConnect:
{
DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
iConnectionQ.Add(&pD->iLink);
m.Complete(KErrNone, EFalse);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT1, this );
return;
}
case EDisconnect:
{
DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
TLocDrv* pL=pD->iDrive;
DMedia* media=pL->iMedia;
if (iState==EReady && media && media->iDriver)
media->iDriver->Disconnect(pD,&m);
else
{
pD->Deque();
m.Complete(KErrNone, EFalse);
}
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT2, this );
return;
}
case DLocalDrive::EForceMediaChange:
{
TUint flags = (TUint) m.Pos();
// if KForceMediaChangeReOpenDriver specified wait for power up,
// and then re-open this drive's media driver
__KTRACE_OPT(KLOCDRV, Kern::Printf("EForceMediaChange, flags %08X\n", flags));
if (flags == (TUint) KForceMediaChangeReOpenMediaDriver)
{
TInt sock;
if (!IsRemovableDevice(sock))
{
CompleteRequest(m, KErrNotSupported);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT3, this );
return;
}
// wait for power up and then call DPrimaryMediaBase::DoRequest()
break;
}
TInt r=ForceMediaChange(flags);
if (r==KErrNone)
{
// wait for media change notification to complete message
m.Forward(&iWaitMedChg,EFalse);
}
else
{
if (r==KErrNotSupported || r==KErrCompletion)
r=KErrNone;
CompleteRequest(m, r);
}
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT4, this );
return;
}
case DLocalDrive::ECaps:
if (iState==EPoweredDown)
{
// The media is powered down, but the media driver still exists.
// - Issue the ECaps request without powering the media back up.
DoRequest(m);
__TRACE_TIMING(0x101);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT5, this );
return;
}
break;
case DLocalDrive::ERead:
case DLocalDrive::EWrite:
case DLocalDrive::EFormat:
case DLocalDrive::EEnlarge:
case DLocalDrive::EReduce:
case DLocalDrive::EPasswordLock:
case DLocalDrive::EPasswordUnlock:
case DLocalDrive::EPasswordClear:
case DLocalDrive::EPasswordErase:
case DLocalDrive::EControlIO:
case DLocalDrive::EDeleteNotify:
case DLocalDrive::EQueryDevice:
#ifdef __DEMAND_PAGING__
case DMediaPagingDevice::ERomPageInRequest:
case DMediaPagingDevice::ECodePageInRequest:
#endif
break;
case DLocalDrive::EGetLastErrorInfo:
{
DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
TLocDrv* pL=pD->iDrive;
*((TErrorInfo*) m.RemoteDes()) = pL->iLastErrorInfo;
CompleteRequest(m, KErrNone);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT6, this );
return;
}
case DLocalDrive::EReadPasswordStore:
{
TPtr8 pswData ((TUint8*) m.RemoteDes(), (TInt) m.Length());
TInt r = ThePasswordStore->ReadPasswordData(pswData);
m.Length() = pswData.Length();
CompleteRequest(m, r);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT7, this );
return;
}
case DLocalDrive::EWritePasswordStore:
{
TPtrC8 pData((TUint8*) m.RemoteDes(), (TInt) m.Length());
TInt r = ThePasswordStore->WritePasswordData(pData);
if(r != KErrNone)
{
CompleteRequest(m, r);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT8, this );
return;
}
r = QuickCheckStatus();
if(r != KErrNone)
{
// Don't try to power up the device if it's not ready.
// - Note that this isn't an error that needs to be returned to the client.
CompleteRequest(m, KErrNone);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT9, this );
return;
}
break;
}
case DLocalDrive::EPasswordStoreLengthInBytes:
{
TInt length = ThePasswordStore->PasswordStoreLengthInBytes();
*(TInt*) m.RemoteDes() = length;
CompleteRequest(m, KErrNone);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT10, this );
return;
}
default:
CHECK_RET(KErrNotSupported);
CompleteRequest(m, KErrNotSupported);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT11, this );
return;
}
__KTRACE_OPT(KFAIL,Kern::Printf("mdrq %d",m.Id()));
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::HandleMsg state %d req %d",iMediaId,iState,m.Id()));
OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DPRIMARYMEDIABASE_HANDLEMSG2, "iMediaId=%d; iState=%d; req Id=%d", iMediaId, iState, m.Id());
// if media driver already open, pass request through
if (iState==EReady)
{
DoRequest(m);
__TRACE_TIMING(0x101);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT12, this );
return;
}
// if open or close in progress, defer this message
if (iState!=EClosed && iState!=EPoweredDown)
{
#ifdef __DEMAND_PAGING__
if (DMediaPagingDevice::PagingRequest(m))
{
__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Deferring PageIn request 0x%08x because opening or closing",&m));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_HANDLEMSG3, "Deferring PageIn request 0x%08x because opening or closing", &m);
iBody->iPagingDevice->SendToDeferredQ(&m);
}
else
#endif
m.Forward(&iDeferred,EFalse);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT13, this );
return;
}
// nothing is open, so try to open something
__ASSERT_ALWAYS(!iCurrentReq,LOCM_FAULT());
#ifdef __DEMAND_PAGING__
#ifdef BTRACE_PAGING_MEDIA
if (DMediaPagingDevice::PagingRequest(m))
BTraceContext12(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInQuietlyDeferred,&m,iState,m.iValue);
#endif // BTRACE_PAGING_MEDIA
#ifdef _DEBUG
__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
if (DMediaPagingDevice::PagingRequest(m))
{
__ASSERT_DEBUG(iPagingMedia,LOCM_FAULT());
__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Page request 0x%08x received -> opening MD",&m));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_HANDLEMSG4, "Page request 0x%08x received; opening MD", &m);
}
#endif // _DEBUG
#endif // __DEMAND_PAGING__
iCurrentReq=&m;
if(iState == EClosed)
{
iState=EPoweringUp1;
}
else if (iState == EPoweredDown)
{
iState=EPoweringUp2;
}
TInt r=InitiatePowerUp();
if (r==KErrNone || r==KErrServerBusy)
{
// wait for completion of power up request
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT14, this );
return;
}
if (r==KErrCompletion)
r=KErrNone; // device already powered up
PowerUpComplete(r);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT15, this );
}
EXPORT_C TInt DPrimaryMediaBase::DoRequest(TLocDrvRequest& m)
/**
If the media exists, it tries to get the partition information if not there.
It then passes on the request to the media driver by calling its Request( ) function.
Then it completes the kernel thread message and the reference count of the thread is closed asynchronously.
@param aRequest Encapsulates the request information received from the client
@return KErrNone, if successful
KErrNotReady, if missing partitions on removable media
KErrNotSupported, if missing partitions on fixed media
KErrArgument Out of range argument ,encapsulated in Local drive request , passed while checking and adjusting for partition
KErrEOF, Reached the end of file
KErrBadDescriptor, if request encapsulates a bad descriptor
Otherwise, one of the other system wide error codes.
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_DOREQUEST_ENTRY, this );
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DPrimaryMediaBase::DoRequest %d",m.Id()));
TLocDrv* pL=m.Drive();
DMedia* media=pL->iMedia;
TInt r=KErrNone;
OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DPRIMARYMEDIABASE_DOREQUEST, "req Id=%d; length=0x%x; position=0x%x", (TInt) m.Id(), (TInt) m.Length(), (TInt) m.Pos());
// re-open this drive's media driver ?
if (m.iValue == DLocalDrive::EForceMediaChange)
{
__ASSERT_DEBUG(((TUint) m.Pos()) == (TUint) KForceMediaChangeReOpenMediaDriver, LOCM_FAULT());
iCurrentReq=NULL;
TLocDrv* pL = m.Drive();
DMedia* media = pL->iMedia;
if (media && media->iDriver)
CloseMediaDrivers(media);
iState=EOpening;
StartOpenMediaDrivers();
NotifyClients(ETrue,pL);
CompleteRequest(m, r);
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_DOREQUEST_EXIT, this, r );
return r;
}
if (!media || !media->iDriver || iState == EClosed)
{
// Return KErrNotReady for missing partitions on removable media
// as opposed to KErrNotSupported for missing partitions on fixed media
// since the latter don't exist whereas the former might exist at some time.
TInt sock;
r=IsRemovableDevice(sock) ? KErrNotReady : KErrNotSupported;
}
iCurrentReq=&m;
if (r==KErrNone)
{
if(iTotalPartitionsOpened == 0)
{
UpdatePartitionInfo();
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_DOREQUEST_EXIT2, this, KErrNone );
return KErrNone;
}
if (!(m.Flags() & TLocDrvRequest::EAdjusted))
{
// If this isn't the only partition, don't allow access to the whole media
if (iTotalPartitionsOpened > 1)
m.DriverFlags() &= ~RLocalDrive::ELocDrvWholeMedia;
r=m.CheckAndAdjustForPartition();
}
if (r==KErrNone)
{
OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_INTERNALS, DPRIMARYMEDIABASE_DOREQUEST_START, "req Id=%d; Remote Thread=0x%x", (TInt) m.Id(), (TUint) m.RemoteThread());
r=media->iDriver->Request(m);
if (r>0)
{
// defer request
#ifdef __DEMAND_PAGING__
if (DMediaPagingDevice::PagingRequest(m))
{
__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Defer PageIn request 0x%08x",&m));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_DOREQUEST2, "Defer PageIn request 0x%08x", &m);
DMediaPagingDevice* pagingdevice=iBody->iPagingDevice;
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
TInt id=m.iValue;
if (id==DMediaPagingDevice::ERomPageInRequest)
{
NKern::FMWait(&pagingdevice->iInstrumentationLock);
if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
pagingdevice->iROMStats.iTotalReDeferrals++;
else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
pagingdevice->iROMStats.iTotalSynchDeferredFromMainQ++;
NKern::FMSignal(&pagingdevice->iInstrumentationLock);
}
else if (m.Flags() & TLocDrvRequest::ECodePaging)
{
NKern::FMWait(&pagingdevice->iInstrumentationLock);
if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
pagingdevice->iCodeStats.iTotalReDeferrals++;
else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
pagingdevice->iCodeStats.iTotalSynchDeferredFromMainQ++;
NKern::FMSignal(&pagingdevice->iInstrumentationLock);
}
else if (m.Flags() & TLocDrvRequest::EDataPaging)
{
NKern::FMWait(&pagingdevice->iInstrumentationLock);
if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
pagingdevice->iDataStats.iTotalReDeferrals++;
else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
pagingdevice->iDataStats.iTotalSynchDeferredFromMainQ++;
NKern::FMSignal(&pagingdevice->iInstrumentationLock);
}
#endif
pagingdevice->SendToDeferredQ(&m);
}
else
#endif
m.Forward(&iDeferred,EFalse);
r=KErrNone;
}
#if defined(__DEMAND_PAGING__) && defined(_DEBUG)
else if (r == KErrNone && DMediaPagingDevice::PagingRequest(m))
{
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("PageIn req 0x%08x completing asynchronously",&m));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_DOREQUEST3, "PageIn req 0x%08x completing asynchronously", &m);
}
#endif
}
}
if (r!=KErrNone && iCurrentReq)
{
TInt s=(r==KErrCompletion)?KErrNone:r;
CHECK_RET(s);
#ifdef __DEMAND_PAGING__
// got here because media driver cannot service or defer this request or did service it synchronously
if (DMediaPagingDevice::PagingRequest(m))
{
__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("media driver cannot service or defer PageIn request 0x%08x or serviced it synchronously (%d)",&m, s));
OstTraceDefExt2(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_DOREQUEST4, "Media driver cannot service or defer PageIn request 0x%08x or serviced it synchronously; retval=%d",(TUint) &m, s);
iBody->iPagingDevice->CompleteRequest(&m, s);
}
else
#endif
CompleteRequest(m, s);
OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_INTERNALS, DPRIMARYMEDIABASE_DOREQUEST_RETURN, "Return req Id=%d; Remote Thread=0x%x; retval=%d", (TInt) m.Id(), (TUint) m.RemoteThread(), (TInt) s);
}
iCurrentReq=NULL;
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_DOREQUEST_EXIT3, this, r );
return r;
}
EXPORT_C void DPrimaryMediaBase::PowerUpComplete(TInt anError)
/**
Called after the device is powered up or there is some error while powering up the device.
If there is an error powering up the devices then it just completes the current running requests with an error
and also completes the outstanding requests on the iDeferred message queue by calling SetClosed( ).
If the device is powered up OK then it either opens the media drivers
and if they are already open then it handles the current/pending requests.
@param anError Error code to be passed on while completing outstanding requests.
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_POWERUPCOMPLETE_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase(%d)::PowerUpComplete err %d iState %d",iMediaId,anError,iState));
OstTraceExt3( TRACE_INTERNALS, DPRIMARYMEDIABASE_POWERUPCOMPLETE, "iMediaId=%d; anError=%d; iState=%d", iMediaId, anError, iState );
if (anError!=KErrNone)
{
// error powering up device
if (iState==EPoweringUp1 || iState==EPoweringUp2)
SetClosed(anError);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_POWERUPCOMPLETE_EXIT, this );
return;
}
// Powered up OK - now open media drivers
if (iState==EPoweringUp1)
{
iState=EOpening;
StartOpenMediaDrivers();
}
else if (iState==EPoweringUp2)
{
// media is powered up and ready, so handle the current/pending requests
MediaReadyHandleRequest();
}
OstTraceFunctionExit1( DPRIMARYMEDIABASE_POWERUPCOMPLETE_EXIT2, this );
}
void DPrimaryMediaBase::CloseMediaDrivers(DMedia* aMedia)
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase(%d)::CloseMediaDrivers",iMediaId));
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS1, "DPrimaryMediaBase iMediaId=%d", iMediaId );
// we mustn't ever close the media driver if it's responsible for data paging as re-opening the drive
// would involve memory allocation which might cause deadlock if the kernel heap were to grow
#ifdef __DEMAND_PAGING__
if (DataPagingDfcQ(this))
{
__KTRACE_OPT(KLOCDRV,Kern::Printf("CloseMediaDrivers aborting for data paging media %08X", this));
OstTrace1(TRACE_FLOW, DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS_EXIT1, "CloseMediaDrivers aborting for data paging media 0x%08x", this);
return;
}
#endif
TInt i;
for (i=0; i<KMaxLocalDrives; i++)
{
TLocDrv* pL=TheDrives[i];
if (pL && pL->iPrimaryMedia==this)
{
__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d",i));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS2, "Drive=%d", i );
if (aMedia == NULL || pL->iMedia == aMedia)
{
pL->iMedia=NULL;
}
}
}
for (i=iLastMediaId; i>=iMediaId; i--)
{
DMedia* pM=TheMedia[i];
if (aMedia == NULL || pM == aMedia)
{
DMediaDriver* pD=pM->iDriver;
pM->iDriver=NULL;
__KTRACE_OPT(KLOCDRV,Kern::Printf("DMedia[%d] @ %08x Driver @ %08x",i,pM,pD));
OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS3, "MediaId=%d; DMedia=0x%08x; MediaDriver=0x%08x", (TInt) i, (TUint) pM, (TUint) pD );
if (pD)
pD->Close();
}
}
__KTRACE_OPT(KLOCDRV,Kern::Printf("<DPrimaryMediaBase(%d)::CloseMediaDrivers",iMediaId));
OstTraceFunctionExit1( DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS_EXIT2, this );
}
void DPrimaryMediaBase::StartOpenMediaDrivers()
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_STARTOPENMEDIADRIVERS_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::StartOpenMediaDrivers",iMediaId));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_STARTOPENMEDIADRIVERS, "DPrimaryMediaBase iMediaId=%d ",iMediaId);
TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
// Get a list of all currently loaded media drivers
// Most media drivers do not make use of the pointer iMountInfo.iInfo when
// their Validate() procedures are called from RPhysicalDeviceArray::GetDriverList().
// However, a group of media drivers sharing the same id (passed in iDevice) may use
// the additional information pointed to by iMountInfo.iInfo to distinguish
// group members. This information is passed when the media driver is registered
// using LocDrv::RegisterMediaDevice().
TInt r=iPhysDevArray.GetDriverList(KLitMediaDriverName,iDevice,iMountInfo.iInfo,ver);
if (r!=KErrNone)
{
// out of memory or no driver exists
SetClosed(r);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_STARTOPENMEDIADRIVERS_EXIT1, this );
return;
}
// Go through them starting with highest priority
iNextMediaId=iMediaId;
iBody->iPhysDevIndex=iPhysDevArray.Count()-1;
iTotalPartitionsOpened=0;
iMediaDriversOpened=0;
iNextMediaDriver=NULL;
OpenNextMediaDriver();
OstTraceFunctionExit1( DPRIMARYMEDIABASE_STARTOPENMEDIADRIVERS_EXIT2, this );
}
void DPrimaryMediaBase::OpenNextMediaDriver()
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_OPENNEXTMEDIADRIVER_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::OpenNextMediaDriver, this %x mediaId %d iBody->iPhysDevIndex %d",iNextMediaId, this, iMediaId, iBody->iPhysDevIndex));
OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_OPENNEXTMEDIADRIVER, "DPrimaryMediaBase iNextMediaId=%d; this=%x; imediaId=%d; iBody->iPhysDevIndex=%d",iNextMediaId, (TUint) this, iMediaId, iBody->iPhysDevIndex);
TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
SPhysicalDeviceEntry& e=iPhysDevArray[iBody->iPhysDevIndex];
DPhysicalDevice* pD=e.iPhysicalDevice;
iState = EOpening;
DMedia* pM=TheMedia[iNextMediaId];
if (pM && pM->iDriver != NULL)
{
iNextMediaDriver = pM->iDriver;
DoOpenMediaDriverComplete(KErrNone);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_OPENNEXTMEDIADRIVER_EXIT1, this );
return;
}
// this may be asynchronous
TInt s=pD->Create( (DBase*&)iNextMediaDriver, iMediaId, (TDesC8*) &iMountInfo, ver);
__KTRACE_OPT(KLOCDRV,Kern::Printf("Media:Open-Opening %o(PRI:%d)-%d",pD,e.iPriority,s));
if (s!=KErrNone)
{
iAsyncErrorCode=s;
iAsyncDfc.Enque();
}
OstTraceFunctionExit1( DPRIMARYMEDIABASE_OPENNEXTMEDIADRIVER_EXIT2, this );
}
// Called when a media driver has responded to the Open request
void DPrimaryMediaBase::DoOpenMediaDriverComplete(TInt anError)
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_DOOPENMEDIADRIVERCOMPLETE_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::DoOpenMediaDriverComplete error %d iNextMediaDriver %x",iNextMediaId,anError,iNextMediaDriver));
OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_DOOPENMEDIADRIVERCOMPLETE, "iMediaId=%d; anError=%d; iNextMediaDriver=0x%x", (TInt) iNextMediaId, (TInt) anError, (TUint) iNextMediaDriver);
if (anError!=KErrNone)
{
DMediaDriver* md = iNextMediaDriver;
iNextMediaDriver = NULL;
if (md)
md->Close();
}
if (anError==KErrNotReady || anError==KErrNoMemory)
{
// if it's not ready or we're out of memory, abort
CloseMediaDrivers();
SetClosed(anError);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DOOPENMEDIADRIVERCOMPLETE_EXIT1, this );
return;
}
if (anError==KErrNone)
{
DMedia* pM=TheMedia[iNextMediaId];
pM->iDriver=iNextMediaDriver;
DPhysicalDevice*& pD=iPhysDevArray[iBody->iPhysDevIndex].iPhysicalDevice;
iNextMediaDriver->iPhysicalDevice=pD;
pD=NULL; // so it won't be closed when we tidy up
++iMediaDriversOpened;
}
// if no error, read partition info on media
iState = EReadPartitionInfo;
if (anError == KErrNone)
{
DMedia* pM=TheMedia[iNextMediaId];
TInt r = pM->iDriver->PartitionInfo(pM->iPartitionInfo);
if (r!=KErrNone)
{
if (r==KErrCompletion)
r=KErrNone;
DoPartitionInfoComplete(r);
}
}
else
{
DoPartitionInfoComplete(anError);
}
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DOOPENMEDIADRIVERCOMPLETE_EXIT2, this );
}
void DPrimaryMediaBase::DoPartitionInfoComplete(TInt anError)
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::DoPartitionInfoComplete error %d",iNextMediaId,anError));
OstTraceExt2( TRACE_INTERNALS, DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE1, "iNextMediaId=%d; anError=%d", iNextMediaId, anError );
DMedia* pM=TheMedia[iNextMediaId];
if (anError==KErrNone || anError == KErrLocked)
{
// successfully read partition info
iTotalPartitionsOpened+=pM->PartitionCount();
}
else
{
// couldn't read partition info or driver failed to open
if (pM->iDriver)
{
#ifdef __DEMAND_PAGING__
if (DataPagingDfcQ(this))
{
__KTRACE_OPT(KLOCDRV,Kern::Printf("DoPartitionInfoComplete(%d) Close Media Driver aborted for data paging media %08X", this));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE2, "Close Media Driver for data paging media 0x%08x", this);
}
else
#endif
{
pM->iDriver->Close();
pM->iDriver=NULL;
}
}
if (anError==KErrNotReady || anError==KErrNoMemory)
{
// if it's not ready or we're out of memory, or the drive is locked, abort
CloseMediaDrivers();
SetClosed(anError);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE_EXIT, this );
return;
}
}
// Open next media driver, if there is one
TBool complete = EFalse;
if (++iNextMediaId>iLastMediaId)
complete=ETrue;
if (iBody->iPhysDevIndex==0)
complete=ETrue;
else
iBody->iPhysDevIndex--;
if (!complete)
{
OpenNextMediaDriver();
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE_EXIT2, this );
return;
}
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase %d All media drivers open & partitions read",iMediaId));
__KTRACE_OPT(KLOCDRV,Kern::Printf("%d media drivers opened",iMediaDriversOpened));
OstTrace1( TRACE_INTERNALS, DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE3, "iMediaDriversOpened=%d", iMediaDriversOpened );
if (iMediaDriversOpened==0)
{
SetClosed(KErrNotSupported);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE_EXIT3, this );
return;
}
// we are now finished with media driver list
iPhysDevArray.Close();
// Finished reading partition info
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase %d Read partition info complete",iMediaId));
__KTRACE_OPT(KLOCDRV,Kern::Printf("%d total partitions",iTotalPartitionsOpened));
OstTraceExt2( TRACE_INTERNALS, DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE4, "Read partition info complete iMediaId=%d; iPartitionsOpened=%d", iMediaId, iTotalPartitionsOpened );
if (iTotalPartitionsOpened==0)
{
SetClosed(KErrNotSupported);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE_EXIT4, this );
return;
}
// work out mapping of drives to partitions/media
TInt totalPartitions=iTotalPartitionsOpened;
TInt id=iMediaId; // start with primary media
TInt partitionsOnThisMedia=PartitionCount();
TInt partition=0;
TInt j;
for (j=0; j<KMaxLocalDrives; j++)
{
TLocDrv* pD=TheDrives[j];
if (pD && pD->iPrimaryMedia==this)
{
if (totalPartitions==0)
{
pD->iMedia=NULL;
continue;
}
if (partition==partitionsOnThisMedia)
{
id++;
partition=0;
partitionsOnThisMedia=TheMedia[id]->PartitionCount();
}
__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d = Media %d Partition %d",j,id,partition));
OstTraceExt3( TRACE_INTERNALS, DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE5, "Local Drive=%d; iMediaId=%d; partition=%d", j, id, partition );
pD->iMedia=TheMedia[id];
pD->iPartitionNumber=partition;
memcpy(pD, pD->iMedia->iPartitionInfo.iEntry+partition, sizeof(TPartitionEntry));
partition++;
totalPartitions--;
}
}
// media is now ready - handle current or deferred requests
MediaReadyHandleRequest();
OstTraceFunctionExit1( DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE_EXIT5, this );
}
void DPrimaryMediaBase::MediaReadyHandleRequest()
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_MEDIAREADYHANDLEREQUEST_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase::MediaReadyHandleRequest() this %x", this));
iState = EReady;
// now we can process the current request
// careful - thread may have exited while we were powering up
if (iCurrentReq)
{
DoRequest(*iCurrentReq); // this sets iCurrentReq=NULL
}
// see if we can process any other requests concurrently
RunDeferred();
OstTraceFunctionExit1( DPRIMARYMEDIABASE_MEDIAREADYHANDLEREQUEST_EXIT, this );
}
void DPrimaryMediaBase::UpdatePartitionInfo()
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_UPDATEPARTITIONINFO_ENTRY, this );
iState=EReadPartitionInfo;
iNextMediaId=iMediaId;
DMedia* pM=TheMedia[iNextMediaId];
TInt r=pM->iDriver->PartitionInfo(pM->iPartitionInfo);
if (r!=KErrNone)
{
if (r==KErrCompletion)
r=KErrNone;
DoPartitionInfoComplete(r);
}
OstTraceFunctionExit1( DPRIMARYMEDIABASE_UPDATEPARTITIONINFO_EXIT, this );
}
void DPrimaryMediaBase::CompleteCurrent(TInt anError)
{
OstTraceFunctionEntryExt( DPRIMARYMEDIABASE_COMPLETECURRENT_ENTRY, this );
if (iCurrentReq)
{
CHECK_RET(anError);
#ifdef __DEMAND_PAGING__
// got here because it was powered down when powering up, or failed powering up or failed opening MD or got media change
if (DMediaPagingDevice::PagingRequest(*iCurrentReq))
{
__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
__ASSERT_ALWAYS( ((iCurrentReq->Flags() & TLocDrvRequest::ECodePaging) == 0) || (iCurrentReq->Drive()->iPagingDrv), LOCM_FAULT());
__KTRACE_OPT2(KLOCDPAGING,KFAIL,Kern::Printf("Got here because it was powered down when powering up, or failed powering up or failed opening MD or got media change"));
OstTraceDef0(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_COMPLETECURRENT, "Completed request due to powered down when powering up, or failed powering up or failed opening MD or got media change");
iBody->iPagingDevice->CompleteRequest(iCurrentReq, anError);
}
else
#endif
CompleteRequest(*iCurrentReq, anError);
iCurrentReq=NULL;
}
OstTraceFunctionExit1( DPRIMARYMEDIABASE_COMPLETECURRENT_EXIT, this );
}
void DPrimaryMediaBase::CompleteRequest(TLocDrvRequest& aMsg, TInt aResult)
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_COMPLETEREQUEST_ENTRY, this );
OstTraceDefExt2(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DPRIMARYMEDIABASE_COMPLETEREQUEST1, "TLocDrvRequest Object=0x%x; aResult=%d", (TUint) &aMsg, aResult);
aMsg.Complete(aResult,EFalse);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_COMPLETEREQUEST_EXIT, this );
}
EXPORT_C void DPrimaryMediaBase::RunDeferred()
/**
Runs deferred Requests. Initiated from DPrimaryMediaBase::PowerUpComplete() function
to see if any other requests can be processed concurrently.
Can also be called from DPrimaryMediaBase::NotifyPowerDown
or DPrimaryMediaBase::NotifyEmergencyPowerDown() function or DMediaDriver::Complete()
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_RUNDEFERRED_ENTRY, this );
// Do nothing if an open or close is in progress - this might be the case, for example,
// if a EForceMediaChange request (with the KForceMediaChangeReOpenMediaDriver flag)
// has recently been processed
if (iState!=EReady && iState!=EClosed && iState!=EPoweredDown)
{
OstTraceFunctionExit1( DPRIMARYMEDIABASE_RUNDEFERRED_EXIT1, this );
return;
}
// rerun deferred requests;
#ifdef __DEMAND_PAGING__
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
TInt countROM=0;
TInt countCode=0;
#endif
if(iPagingMedia)
{
__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
if(iBody->iPagingDevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ) // if already emptying deferred page in queue, don't reenter
{
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Already emptying deferred queue"));
OstTrace0(TRACE_FLOW, DPRIMARYMEDIABASE_RUNDEFERRED_EXIT2, "< Already emptying deferred queue");
return;
}
DMediaPagingDevice* pagingdevice=iBody->iPagingDevice;
TLocDrvRequest* pL = (TLocDrvRequest*) pagingdevice->iDeferredQ.Last();
if(pL)
{
pagingdevice->iEmptyingQ|= DMediaPagingDevice::EDeferredQ; // prevent reentering when already emptying this queue
TLocDrvRequest* pM=NULL;
while (pM != pL && (pM = (TLocDrvRequest*) pagingdevice->iDeferredQ.Poll()) != NULL) // synchronously empty deferred queue but ignore re-deferrals
{
__ASSERT_ALWAYS( DMediaPagingDevice::PagingRequest(*pL), LOCM_FAULT() );
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
(pM->iValue==DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
if(pM==pL)
{
NKern::FMWait(&pagingdevice->iInstrumentationLock);
if(pM->iValue==DMediaPagingDevice::ERomPageInRequest && pagingdevice->iROMStats.iMaxReqsInDeferred<countROM)
pagingdevice->iROMStats.iMaxReqsInDeferred=countROM;
else if ((pM->Flags() & TLocDrvRequest::ECodePaging) && pagingdevice->iCodeStats.iMaxReqsInDeferred<countCode)
pagingdevice->iCodeStats.iMaxReqsInDeferred=countCode;
else if ((pM->Flags() & TLocDrvRequest::EDataPaging) && pagingdevice->iDataStats.iMaxReqsInDeferred<countCode)
pagingdevice->iDataStats.iMaxReqsInDeferred=countCode;
NKern::FMSignal(&pagingdevice->iInstrumentationLock);
}
#endif
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("RunDeferred: process req 0x%08x, last in deferred queue 0x%08x",pM,pL));
OstTraceDefExt2(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_RUNDEFERRED2, "process req=0x%08x; last in deferred queue=0x%08x",(TUint) pM, (TUint) pL);
#ifdef BTRACE_PAGING_MEDIA
BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInDeferredReposted,pM,pM->iValue);
#endif
// if Page In requests are synchronous this services them all in sequence,
// if they're asynch it re-defers them
DoRequest(*(TLocDrvRequest*)pM);
}
pagingdevice->iEmptyingQ&= ~DMediaPagingDevice::EDeferredQ;
}
// the reason we now try an empty the main Page In queue is there is at least one type of Page In request
// serviced synchronously in which case when we empty the deferred Page In queue as above, received Page In
// requests are left in the main queue (not deferred) and we don't want to start processing deferred normal
// requests before these Page In requests. If all deferred normal requests are synchronous, the received Page
// In requests will have to wait until all are serviced. NB: requests may be deferred even if the MD services
// all requests synchronously, but runs background tasks that cannot be interrupted. In this last case the
// normal deferred queue may have some very long latency requests.
if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ) // already emptying main Page In queue, skip (any Page In requests will be deferred)
{
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Already emptying main queue"));
OstTrace0(TRACE_FLOW, DPRIMARYMEDIABASE_RUNDEFERRED_EXIT3, "< Already emptying main queue");
return;
}
TLocDrvRequest* pM=NULL;
if (!pagingdevice->iMainQ.iReady) // if it's ready, then queue is empty
{
pM = (TLocDrvRequest*) pagingdevice->iMainQ.iMessage;
pagingdevice->iMainQ.iMessage = NULL;
if (pM == NULL)
pM = (TLocDrvRequest*) pagingdevice->iMainQ.Poll();
}
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
countROM = countCode=0;
#endif
if(pM)
{
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
__e32_atomic_add_ord32(&pagingdevice->iROMStats.iTotalSynchEmptiedMainQ, 1);
#endif
pagingdevice->iEmptyingQ|=DMediaPagingDevice::EMainQ;
for ( ; pM != NULL; pM = (TLocDrvRequest*) pagingdevice->iMainQ.Poll())
{
__ASSERT_ALWAYS(DMediaPagingDevice::PagingRequest(*pM), LOCM_FAULT());
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
(pM->iValue==DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
#endif
__KTRACE_OPT(KLOCDPAGING,Kern::Printf("RunDeferred: process req 0x%08x",pM));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_RUNDEFERRED4, "process req=0x%08x", pM);
DoRequest(*(TLocDrvRequest*)pM); // if Page In requests are synchronous this services them all in sequence, if they're asynch it defers them
}
pagingdevice->iEmptyingQ&= ~DMediaPagingDevice::EMainQ;
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
NKern::FMWait(&pagingdevice->iInstrumentationLock);
pagingdevice->iROMStats.iTotalSynchServicedFromMainQ+=countROM;
if(pagingdevice->iROMStats.iMaxReqsInPending<countROM)
pagingdevice->iROMStats.iMaxReqsInPending=countROM;
pagingdevice->iCodeStats.iTotalSynchServicedFromMainQ+=countCode;
if(pagingdevice->iCodeStats.iMaxReqsInPending<countCode)
pagingdevice->iCodeStats.iMaxReqsInPending=countCode;
NKern::FMSignal(&pagingdevice->iInstrumentationLock);
#endif
} // if (pM)
} // if(iPagingMedia)
#endif
if (iRunningDeferred)
{
OstTraceFunctionExit1( DPRIMARYMEDIABASE_RUNDEFERRED_EXIT4, this );
return;
}
TMessageBase* pL = iDeferred.Last();
if (!pL)
{
OstTraceFunctionExit1( DPRIMARYMEDIABASE_RUNDEFERRED_EXIT5, this );
return; // no deferred requests
}
iRunningDeferred=1;
TMessageBase* pM=NULL;
while( pM != pL && (pM=iDeferred.Poll()) != NULL) // stop after processing last one (requests may be re-deferred)
DoRequest(*(TLocDrvRequest*)pM);
iRunningDeferred=0;
OstTraceFunctionExit1( DPRIMARYMEDIABASE_RUNDEFERRED_EXIT6, this );
}
void DPrimaryMediaBase::SetClosed(TInt anError)
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_SETCLOSED_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::SetClosed error %d",iMediaId,anError));
OstTraceExt2( TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_SETCLOSED, "iMediaId=%d; anError=%d", iMediaId, anError );
CHECK_RET(anError);
// cancel DMediaDriver::OpenMediaDriverComplete() / DMediaDriver::PartitionInfoComplete() DFC
iAsyncDfc.Cancel();
iDeferred.CompleteAll(anError);
#ifdef __DEMAND_PAGING__
if(iPagingMedia)
iBody->iPagingDevice->iDeferredQ.CompleteAll(anError);
#endif
CompleteCurrent(anError);
if (iState==EOpening)
iPhysDevArray.Close();
iState = EClosed;
iWaitMedChg.CompleteAll(KErrNone);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_SETCLOSED_EXIT, this );
}
void DPrimaryMediaBase::NotifyClients(TBool aMediaChange,TLocDrv* aLocDrv)
//
// Notify all clients of a media change or power-down event
//
{
OstTraceFunctionEntryExt( DPRIMARYMEDIABASE_NOTIFYCLIENTS_ENTRY, this );
SDblQueLink* pL=iConnectionQ.iA.iNext;
while (pL!=&iConnectionQ.iA)
{
DLocalDrive* pD=_LOFF(pL,DLocalDrive,iLink);
// Issue the notification if the caller wants to notify all drives (aLocDrv == NULL) or
// the specified drive matches this one
if (aLocDrv == NULL || aLocDrv == pD->iDrive)
pD->NotifyChange(*this, aMediaChange);
pL=pL->iNext;
}
OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYCLIENTS_EXIT, this );
}
EXPORT_C void DPrimaryMediaBase::NotifyMediaChange()
/**
Closes all media drivers on this device and notifies all connections that media change has occurred
and completes any outstanding requests with KErrNotReady.
This also completes any force media change requests with KErrNone.
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_NOTIFYMEDIACHANGE_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyMediaChange state %d",iMediaId,iState));
OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_NOTIFYMEDIACHANGE, "iMediaId=%d; iState=%d", iMediaId, iState );
TInt state=iState;
__ASSERT_DEBUG(iBody, LOCM_FAULT());
#ifdef __DEMAND_PAGING__
iBody->iMediaChanges++;
// As data paging media never close, need to ensure the media driver cancels
// any requests it owns as the stack may be powered down by DPBusPrimaryMedia::ForceMediaChange().
// DMediaDriver::NotifyPowerDown() should do this
if(DataPagingDfcQ(this))
NotifyPowerDown();
#endif
// complete any outstanding requests with KErrNotReady
// and any force media change requests with KErrNone
SetClosed(KErrNotReady);
// close all media drivers on this device
if (state>=EOpening)
{
CloseMediaDrivers();
}
// notify all connections that media change has occurred
NotifyClients(ETrue);
// complete any force media change requests
iWaitMedChg.CompleteAll(KErrNone);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYMEDIACHANGE_EXIT, this );
}
EXPORT_C void DPrimaryMediaBase::NotifyPowerDown()
/**
Called on machine power-down. Notifies all media drivers on this device.
If device is not ready then it completes current requests but leaves other outstanding requests
If ready, media driver should complete current request.
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_NOTIFYPOWERDOWN_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyPowerDown state %d",iMediaId,iState));
OstTraceExt2( TRACE_INTERNALS, DPRIMARYMEDIABASE_NOTIFYPOWERDOWN, "iMediaId=%d; iState=%d", iMediaId, iState );
TInt id;
TBool allPersistent = ETrue;
TBool allOpen = ETrue;
// notify all media drivers on this device
for (id=iMediaId; id<=iLastMediaId; id++)
{
DMedia* pM = TheMedia[id];
DMediaDriver* pD = pM->iDriver;
if ((pD) && (iState==EReady || iState==EReadPartitionInfo || iState==EOpening || iState==EPoweringUp2 || iState==ERecovering))
pD->NotifyPowerDown();
if (pD == NULL || pD->iPhysicalDevice == NULL)
allOpen = EFalse;
else if (pD->iPhysicalDevice->Info(DPhysicalDevice::EMediaDriverPersistent, NULL) != KErrNone)
{
// We must NOT destroy the media driver if this media is responsible for data paging as
// re-opening the media driver would involve memory allocation which might cause a deadlock
#ifdef __DEMAND_PAGING__
__ASSERT_ALWAYS(!DataPagingDfcQ(this), LOCM_FAULT());
#endif
allPersistent = EFalse;
}
}
__KTRACE_OPT(KLOCDRV,Kern::Printf("allPersistent(%d)::allOpen %d",allPersistent, allOpen));
OstTraceExt2( TRACE_INTERNALS, DPRIMARYMEDIABASE_NOTIFYPOWERDOWN2, "allPersistent=%d; allOpen=%d", allPersistent, allOpen );
if (allPersistent && allOpen && iState == EReady)
{
//
// The EPoweredDown state indicates that the media is powered down, but the media driver still exists.
//
// - This allows the media driver to still be accessed (ie - to determine driver capabilities) without
// the need to power up the device, which can be a lengthy operation.
//
// - NOTE : This will need re-visiting if we ever re-enable standby mode on a platform that is not capable
// of detecting door interrupts while in standby. In such a scenario, problems could occur as
// the device capabilities may change without the local media subsystem recognising.
//
iState=EPoweredDown;
}
else
{
CloseMediaDrivers();
SetClosed(KErrNotReady);
}
NotifyClients(EFalse);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYPOWERDOWN_EXIT, this );
}
EXPORT_C void DPrimaryMediaBase::NotifyPsuFault(TInt anError)
/**
Closes all media drivers on this device and completes any outstanding requests with error code.
@param anError Error code to be passed on while closing media drivers and completing outstanding requests.
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_NOTIFYPSUFAULT_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyPsuFault state %d, err %d",iMediaId,iState,anError));
OstTraceExt3( TRACE_INTERNALS, DPRIMARYMEDIABASE_NOTIFYPSUFAULT, "iMediaId=%d; iState=%d; anError=%d", iMediaId, iState, anError );
if (iState>=EOpening)
{
CloseMediaDrivers();
}
// complete any outstanding requests with error
SetClosed(anError);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYPSUFAULT_EXIT, this );
}
EXPORT_C void DPrimaryMediaBase::NotifyEmergencyPowerDown()
/**
Called on emergency power down. Notifies all media drivers on this device.
If it is not in a ready state then it completes the current request but leaves other outstanding requests.
If it is ready then the media driver should complete the current request.
It closes all media drivers and notifies all clients of a power down event.
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_NOTIFYEMERGENCYPOWERDOWN_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyEmergencyPowerDown state %d",iMediaId,iState));
OstTraceExt2( TRACE_INTERNALS, DPRIMARYMEDIABASE_NOTIFYEMERGENCYPOWERDOWN, "iMediaId=%d; iState=%d", iMediaId, iState );
TBool recover=EFalse;
if (iState==EReady && iCritical!=0)
{
// check if emergency power recovery supported
;
}
if (recover)
{
}
// else just return KErrAbort
// notify all media drivers on this device
if (iState==EReady || iState==EOpening || iState==EPoweringUp2 || iState==ERecovering)
{
TInt id;
for (id=iMediaId; id<=iLastMediaId; id++)
{
DMedia* pM=TheMedia[id];
DMediaDriver* pD=pM->iDriver;
if (pD)
pD->NotifyEmergencyPowerDown();
}
}
if (iState!=EReady)
{
// complete current request but leave other outstanding requests
// if ready, media driver should complete current request
CompleteCurrent(KErrNotReady);
}
CloseMediaDrivers();
SetClosed(KErrNotReady);
NotifyClients(EFalse);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYEMERGENCYPOWERDOWN_EXIT, this );
}
EXPORT_C void DPrimaryMediaBase::NotifyMediaPresent()
/**
Notifies clients of a media change by calling NotifyClients ( ) function to indicate that media is present.
*/
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_NOTIFYMEDIAPRESENT_ENTRY, this );
NotifyClients(ETrue);
OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYMEDIAPRESENT_EXIT, this );
}
EXPORT_C TInt DPrimaryMediaBase::DoInCritical()
/**
Flags the media driver as entering a critical part of its processing.
In this context, critical means that the driver must be allowed to complete
its current activity.
For example, a request to power down the device must be deferred until
the driver exits the critical part.
@return KErrNone, if the driver has been successfully flagged as being in
a critical part; otherwise, one of the other system-wide error codes.
The default implementation just returns KErrNone and can be overridden in the derived class
@see DPrimaryMediaBase::DoEndInCritical()
*/
{
return KErrNone;
}
EXPORT_C void DPrimaryMediaBase::DoEndInCritical()
/**
Flags the media driver as leaving a critical part of its processing.
Default implementation does nothing
@see DPrimaryMediaBase::DoEndInCritical()
*/
{
}
TInt DPrimaryMediaBase::InCritical()
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_INCRITICAL_ENTRY, this );
if (iCritical==0)
{
TInt r=DoInCritical();
if (r!=KErrNone)
{
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_INCRITICAL_EXIT1, this, r );
return r;
}
}
++iCritical;
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_INCRITICAL_EXIT2, this, KErrNone );
return KErrNone;
}
void DPrimaryMediaBase::EndInCritical()
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_ENDINCRITICAL_ENTRY, this );
if (--iCritical==0)
DoEndInCritical();
OstTraceFunctionExit1( DPRIMARYMEDIABASE_ENDINCRITICAL_EXIT, this );
}
EXPORT_C void DPrimaryMediaBase::DeltaCurrentConsumption(TInt /*aCurrent*/)
/**
Sets the incremental value of current consumption to aCurrent.
The default implementation does nothing .
@param aCurrent Delta Current in Milliamps
*/
{
// default implementation
}
TInt DPrimaryMediaBase::OpenMediaDriver()
//
// Synchronous open for devices with no DFC queue (e.g. IRAM)
//
{
OstTraceFunctionEntry1( DPRIMARYMEDIABASE_OPENMEDIADRIVER_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase:OpenMediaDriver-%d",iMediaId));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_OPENMEDIADRIVER1, "iMediaId=%d", iMediaId);
TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
// Get a list of all currently loaded media drivers
// Most media drivers do not make use of the pointer iMountInfo.iInfo when
// their Validate() procedures are called from RPhysicalDeviceArray::GetDriverList().
// However, a group of media drivers sharing the same id (passed in iDevice) may use
// the additional information pointed to by iMountInfo.iInfo to distinguish
// group members. This information is passed when the media driver is registered
// using LocDrv::RegisterMediaDevice().
TInt r=iPhysDevArray.GetDriverList(KLitMediaDriverName,iDevice,iMountInfo.iInfo,ver);
if (r!=KErrNone)
{
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_OPENMEDIADRIVER_EXIT1, this, r );
return r;
}
// Go through them starting with highest priority
TInt totalPartitions=0;
TInt c=iPhysDevArray.Count(); // can't be zero
TInt i=c-1;
r=KErrNotSupported;
for (iNextMediaId=iMediaId; i>=0 && iNextMediaId<=iLastMediaId && r!=KErrNotReady; i--)
{
DPhysicalDevice* pD=iPhysDevArray[i].iPhysicalDevice;
DMediaDriver *pM=NULL;
// try to open media driver
TInt s=pD->Create( (DBase*&)pM, iMediaId, NULL, ver);
__KTRACE_OPT(KLOCDRV,Kern::Printf("Media:Open-Opening %o(PRI:%d)-%d",pD,iPhysDevArray[i].iPriority,s));
OstTraceDefExt3(OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_OPENMEDIADRIVER2, "Media:Open-Opening 0x%x iPriority=%d; retval=%d", (TUint) pD, (TUint) iPhysDevArray[i].iPriority, (TUint) s);
if (s!=KErrNone && pM)
{
pM->Close();
pM=NULL;
}
if (s==KErrNotReady)
{
r=KErrNotReady; // If it isn't ready - nothing will open.
break;
}
if (s==KErrNoMemory)
{
r=KErrNoMemory; // If we are out of memory, give up now
break;
}
if (s==KErrNone)
{
// Found a media driver for this device - check for valid partitions.
DMedia* media=TheMedia[iNextMediaId];
s=pM->PartitionInfo(media->iPartitionInfo);
if (s==KErrNone)
{
r=KErrNone;
media->iDriver=pM;
pM->iPhysicalDevice=pD;
iPhysDevArray[i].iPhysicalDevice=NULL; // so it won't be closed when we tidy up
totalPartitions+=media->PartitionCount();
}
else
pM->Close();
}
}
// we are now finished with media driver list
iPhysDevArray.Close();
// if driver opened OK, work out mapping of drives to partitions/media
if (r==KErrNone)
{
TInt id=iMediaId; // start with primary media
TInt partitionsOnThisMedia=PartitionCount();
TInt partition=0;
TInt j;
for (j=0; j<KMaxLocalDrives; j++)
{
TLocDrv* pD=TheDrives[j];
if (pD && pD->iPrimaryMedia==this)
{
if (totalPartitions==0)
{
pD->iMedia=NULL;
continue;
}
if (partition==partitionsOnThisMedia)
{
id++;
partition=0;
partitionsOnThisMedia=TheMedia[id]->PartitionCount();
}
pD->iMedia=TheMedia[id];
pD->iPartitionNumber=partition;
memcpy(pD, pD->iMedia->iPartitionInfo.iEntry+partition, sizeof(TPartitionEntry));
partition++;
totalPartitions--;
}
}
}
__KTRACE_OPT(KLOCDRV,Kern::Printf("<DPrimaryMediaBase:OpenMediaDriver-%d",r));
OstTraceFunctionExitExt( DPRIMARYMEDIABASE_OPENMEDIADRIVER_EXIT2, this, r );
return r;
}
#ifdef __DEMAND_PAGING__
// RequestCountInc()
//
// Counts the number of outstanding requests
// For data-paging media, calls DPagingDevice::NotifyBusy() when count goes positive
//
void DPrimaryMediaBase::RequestCountInc()
{
__ASSERT_DEBUG(iBody, LOCM_FAULT());
TInt oldVal = (TInt) __e32_atomic_add_ord32(&iBody->iRequestCount, (TUint) 1);
//Kern::Printf("RCINC: this %x cnt %d, old %d", this, iBody->iRequestCount, oldVal);
OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_REQUESTCOUNTINC, "new count=%d; old count=%d", iBody->iRequestCount, oldVal );
if (oldVal == 0 && iBody->iPagingDevice)
{
//Kern::Printf("RCINC: NotifyBusy()");
iBody->iPagingDevice->NotifyBusy();
}
}
// RequestCountDec()
//
// Counts the number of outstanding requests
// For data-paging media, calls DPagingDevice::NotifyIdle() when count reaches zero
//
void DPrimaryMediaBase::RequestCountDec()
{
__ASSERT_DEBUG(iBody, LOCM_FAULT());
TInt oldVal = (TInt) __e32_atomic_add_ord32(&iBody->iRequestCount, (TUint) -1);
//Kern::Printf("RCDEC: this %x cnt %d, old %d", this, iBody->iRequestCount, oldVal);
OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_REQUESTCOUNTDEC, "new count=%d; old count=%d", iBody->iRequestCount, oldVal );
if (oldVal == 1 && iBody->iPagingDevice)
{
//Kern::Printf("RCDEC: NotifyIdle()");
iBody->iPagingDevice->NotifyIdle();
}
__ASSERT_DEBUG(iBody->iRequestCount >= 0, LOCM_FAULT());
}
#endif // __DEMAND_PAGING__
TPartitionInfo::TPartitionInfo()
//
// Constructor
//
{
memclr(this, sizeof(TPartitionInfo));
}
#ifdef __DEMAND_PAGING__
void pageInDfc(TAny* aPtr)
{
OstTraceFunctionEntry0( _PAGEINDFC_ENTRY );
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("pageInDfc"));
DPrimaryMediaBase* primaryMedia=(DPrimaryMediaBase*)aPtr;
__ASSERT_ALWAYS(primaryMedia && primaryMedia->iPagingMedia && primaryMedia->iBody->iPagingDevice,LOCM_FAULT());
DMediaPagingDevice* pagingdevice=primaryMedia->iBody->iPagingDevice;
TLocDrvRequest* m = (TLocDrvRequest*) pagingdevice->iMainQ.iMessage;
pagingdevice->iMainQ.iMessage = NULL;
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
if (!m)
__e32_atomic_add_ord8(&pagingdevice->iROMStats.iTotalRunDry, 1);
#endif
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
TInt countROM=0;
TInt countCode=0;
#endif
for ( ; m != NULL; m = (TLocDrvRequest*) pagingdevice->iMainQ.Poll())
{
__ASSERT_ALWAYS(DMediaPagingDevice::PagingRequest(*m), LOCM_FAULT());
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
(m->iValue == DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
#endif
__KTRACE_OPT(KLOCDPAGING, Kern::Printf("pageInDfc: process request 0x%08x, last in queue 0x%08x",m, pagingdevice->iMainQ.Last()) );
OstTraceDefExt2(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, PAGEINDFC2, "process request=0x%08x; last in queue=0x%08x",(TUint) m, (TUint) pagingdevice->iMainQ.Last());
primaryMedia->HandleMsg(*m);
}
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
NKern::FMWait(&pagingdevice->iInstrumentationLock);
if (pagingdevice->iROMStats.iMaxReqsInPending<countROM)
pagingdevice->iROMStats.iMaxReqsInPending=countROM;
if (pagingdevice->iCodeStats.iMaxReqsInPending<countCode)
pagingdevice->iCodeStats.iMaxReqsInPending=countCode;
NKern::FMSignal(&pagingdevice->iInstrumentationLock);
#endif
pagingdevice->iMainQ.Receive(); // allow reception of more messages
OstTraceFunctionExit0( _PAGEINDFC_EXIT );
}
DMediaPagingDevice::DMediaPagingDevice(DPrimaryMediaBase* aPtr)
: iMainQ(pageInDfc, aPtr, NULL, KMaxDfcPriority),
iDeferredQ(NULL, NULL, NULL, 0), // callback never used
iEmptyingQ(NULL),
iInstrumentationLock()
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
,iServicingROM(NULL), iServicingCode(NULL)
#endif
{
OstTraceFunctionEntry1( DMEDIAPAGINGDEVICE_DMEDIAPAGINGDEVICE_CONSTRUCTOR_ENTRY, this );
iPrimaryMedia = aPtr;
if (iPrimaryMedia->iDfcQ) // media driver has its own thread
{
iMainQ.SetDfcQ(iPrimaryMedia->iDfcQ);
}
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
memclr((TAny*)&iROMStats,sizeof(SMediaROMPagingConcurrencyInfo)+sizeof(SMediaCodePagingConcurrencyInfo));
#endif
#ifdef __DEMAND_PAGING_BENCHMARKS__
iROMBenchmarkData.iCount=iROMBenchmarkData.iTotalTime=iROMBenchmarkData.iMaxTime=0;
iROMBenchmarkData.iMinTime = KMaxTInt;
iCodeBenchmarkData.iCount=iCodeBenchmarkData.iTotalTime=iCodeBenchmarkData.iMaxTime=0;
iCodeBenchmarkData.iMinTime = KMaxTInt;
iDataInBenchmarkData.iCount=iDataInBenchmarkData.iTotalTime=iDataInBenchmarkData.iMaxTime=0;
iDataInBenchmarkData.iMinTime = KMaxTInt;
iDataOutBenchmarkData.iCount=iDataOutBenchmarkData.iTotalTime=iDataOutBenchmarkData.iMaxTime=0;
iDataOutBenchmarkData.iMinTime = KMaxTInt;
#endif
iMainQ.Receive();
OstTraceFunctionExit1( DMEDIAPAGINGDEVICE_DMEDIAPAGINGDEVICE_CONSTRUCTOR_EXIT, this );
}
DMediaPagingDevice::~DMediaPagingDevice()
{
OstTraceFunctionEntry1( DMEDIAPAGINGDEVICE_DMEDIAPAGINGDEVICE_DESTRUCTOR_ENTRY, this );
if (iMountInfoDataLock)
ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDataLock);
if (iMountInfoDescHdrLock)
ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDescHdrLock);
if (iMountInfoDescLenLock)
ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDescLenLock);
OstTraceFunctionExit1( DMEDIAPAGINGDEVICE_DMEDIAPAGINGDEVICE_DESTRUCTOR_EXIT, this );
}
void DMediaPagingDevice::SendToMainQueueDfcAndBlock(TThreadMessage* aMsg)
{
OstTraceFunctionEntryExt( DMEDIAPAGINGDEVICE_SENDTOMAINQUEUEDFCANDBLOCK_ENTRY, this );
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("Send request 0x%08x to main queue",aMsg));
__ASSERT_ALWAYS(aMsg->iState==TMessageBase::EFree,LOCM_FAULT()); // check that message was previously completed or never queued
// if drive supports DMA, turn on Physical memory flag & sync memory
TLocDrvRequest& m=*(TLocDrvRequest*)(aMsg);
TLinAddr addr = (TLinAddr) m.RemoteDes();
TInt len = I64LOW(m.Length());
TBool needSyncAfterRead = EFalse;
if (m.Drive()->iDmaHelper)
{
m.Flags() |= TLocDrvRequest::EPhysAddr;
if (m.Id() == DLocalDrive::EWrite)
{
Cache::SyncMemoryBeforeDmaWrite(addr, len);
}
else
{
Cache::SyncMemoryBeforeDmaRead(addr, len);
needSyncAfterRead = ETrue;
}
}
// Count the number of outstanding requests if this is the data-paging media, so that
// we can call DPagingDevice::NotifyBusy() / DPagingDevice::NotifyIdle()
if ((m.Flags() & TLocDrvRequest::EBackgroundPaging) == 0)
iPrimaryMedia->RequestCountInc();
aMsg->SendReceive(&iMainQ);
#ifdef __DEMAND_PAGING__
if ((m.Flags() & TLocDrvRequest::EBackgroundPaging) == 0)
iPrimaryMedia->RequestCountDec();
#endif
if (needSyncAfterRead)
{
Cache::SyncMemoryAfterDmaRead(addr, len);
}
// come back here when request is completed
__ASSERT_DEBUG(aMsg->iState==TMessageBase::EFree,LOCM_FAULT()); // check message has been completed
OstTraceFunctionExit1( DMEDIAPAGINGDEVICE_SENDTOMAINQUEUEDFCANDBLOCK_EXIT, this );
}
void DMediaPagingDevice::SendToDeferredQ(TThreadMessage* aMsg)
{
OstTraceFunctionEntryExt( DMEDIAPAGINGDEVICE_SENDTODEFERREDQ_ENTRY, this );
// This queue is only accessed from MD thread
__ASSERT_ALWAYS(aMsg->iState==TMessageBase::EAccepted,LOCM_FAULT()); // check that message was previously dequeued
#ifdef BTRACE_PAGING_MEDIA
if(iEmptyingQ&DMediaPagingDevice::EDeferredQ) // already deferring
BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInReDeferred,aMsg,aMsg->iValue);
else
BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInDeferred,aMsg,aMsg->iValue);
#endif
aMsg->Forward(&iDeferredQ, EFalse);
OstTraceFunctionExit1( DMEDIAPAGINGDEVICE_SENDTODEFERREDQ_EXIT, this );
}
void DMediaPagingDevice::CompleteRequest(TThreadMessage* aMsg, TInt aResult)
{
OstTraceFunctionEntryExt( DMEDIAPAGINGDEVICE_COMPLETEREQUEST_ENTRY, this );
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::CompleteRequest, request 0x%08x result %d", aMsg, aResult));
__ASSERT_DEBUG(aMsg->iState==TMessageBase::EAccepted,LOCM_FAULT());
#ifdef BTRACE_PAGING_MEDIA
BTraceContext12(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInPagedIn,aMsg,aResult,aMsg->iValue);
#endif
iPrimaryMedia->CompleteRequest(*((TLocDrvRequest*) aMsg), aResult);
OstTraceFunctionExit1( DMEDIAPAGINGDEVICE_COMPLETEREQUEST_EXIT, this );
}
TInt DMediaPagingDevice::Read(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TInt aDrvNumber)
{
OstTraceFunctionEntry1( DMEDIAPAGINGDEVICE_READ_ENTRY, this );
__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT()); // that would lock up the system, thus better die now
__ASSERT_ALWAYS(aReq,LOCM_FAULT());
__ASSERT_CRITICAL
#ifdef __DEMAND_PAGING_BENCHMARKS__
TUint32 bmStart = NKern::FastCounter();
#endif
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
TUint8* servicingCount;
NKern::FMWait(&iInstrumentationLock);
if(aDrvNumber == EDriveRomPaging) // ROM paging
{
servicingCount = &iServicingROM;
if(iServicingROM)
iROMStats.iTotalConcurrentReqs++;
if(!(++iServicingROM))
{
iServicingROM=1; // overflow...
iROMStats.iTotalConcurrentReqs=0; // ...reset this
}
TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
if(!empty)
iROMStats.iTotalReqIssuedNonEmptyQ++;
}
else if (aDrvNumber == EDriveDataPaging) // Data paging
{
servicingCount = &iServicingDataIn;
if(iServicingDataIn)
iDataStats.iTotalConcurrentReqs++;
if(!(++iServicingDataIn))
{
iServicingDataIn=1; // overflow...
iDataStats.iTotalConcurrentReqs=0; // ...reset this
}
TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
if(!empty)
iDataStats.iTotalReqIssuedNonEmptyQ++;
}
else
{
servicingCount = &iServicingCode;
if(iServicingCode)
iCodeStats.iTotalConcurrentReqs++;
if(!(++iServicingCode))
{
iServicingCode=1; // overflow...
iCodeStats.iTotalConcurrentReqs=0; // ...reset this
}
TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
if(!empty)
iCodeStats.iTotalReqIssuedNonEmptyQ++;
}
NKern::FMSignal(&iInstrumentationLock);
#endif
TUint offset=aOffset<<iReadUnitShift;
TUint size=aSize<<iReadUnitShift;
#ifdef BTRACE_PAGING_MEDIA
TInt buf[3];
buf[0]=size; // page in request length
buf[1]=aDrvNumber; // local drive number (-1 if ROM)
buf[2]=(TInt)aReq; // address of request object
BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInBegin,aBuffer,offset,buf,sizeof(buf));
#endif
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::Read, Req(0x%08x), Buff(0x%x),Offset(%d),Size(%d),DrvNo(%d)",aReq,aBuffer,offset,size,aDrvNumber));
OstTraceDefExt5(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DMEDIAPAGINGDEVICE_READ1, "req=0x%08x; aBuffer=0x%x; offset=%d; size=%d; aDrvNumber=%d", (TUint) aReq, (TInt) aBuffer, (TInt) offset, (TUint) size, (TUint) aDrvNumber);
// no DFCQ, media driver executes in the context of calling thread
if (!iPrimaryMedia->iDfcQ)
{
LOCM_FAULT(); // don't allow paging
OstTraceFunctionExitExt( DMEDIAPAGINGDEVICE_READ_EXIT, this, KErrNone );
return KErrNone; // keep compiler happy
}
TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
#ifdef __DEMAND_PAGING_BENCHMARKS__
SPagingBenchmarkInfo* info = NULL;
#endif
// Read from the media and allow for retries in the unlikely event of an error.
const TInt KPageInRetries = 5;
TInt retVal = KErrGeneral;
for (TInt i=0; retVal != KErrNone && i < KPageInRetries; i++)
{
m.Flags() = TLocDrvRequest::EPaging;
TLocDrv* pL=NULL;
if(aDrvNumber == EDriveRomPaging) // ROM paging
{
m.Id() = DMediaPagingDevice::ERomPageInRequest;
if (iRomPagingDriveNumber == KErrNotFound)
{
// ROM partition has not been reported by the media driver
// it is assumed that the media driver will adjust the request accordingly
m.Flags() |= TLocDrvRequest::EAdjusted;
// Use a media drive number so the request reaches the correct media...
m.Drive() = TheDrives[iFirstLocalDriveNumber];
}
else
{
//ROM partition has been reported
//Set drive for use with CheckAndAdjustForPartition
m.Drive() = TheDrives[iRomPagingDriveNumber];
}
#ifdef __DEMAND_PAGING_BENCHMARKS__
__e32_atomic_add_ord32(&iMediaPagingInfo.iRomPageInCount, (TUint) 1);
info = &iROMBenchmarkData;
#endif
}
else if(aDrvNumber == EDriveDataPaging) // Data paging
{
m.Id() = DLocalDrive::ERead;
m.Flags() |= TLocDrvRequest::EDataPaging;
m.Drive() = TheDrives[iDataPagingDriveNumber];
#ifdef __DEMAND_PAGING_BENCHMARKS__
__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageInCount, (TUint) 1);
info = &iDataInBenchmarkData;
#endif
}
else if ((aDrvNumber >=0) && (aDrvNumber<KMaxLocalDrives)) // Code paging
{
m.Id() = DMediaPagingDevice::ECodePageInRequest;
m.Flags() |= TLocDrvRequest::ECodePaging;
pL=TheDrives[aDrvNumber];
__ASSERT_DEBUG(pL&&(pL->iPrimaryMedia==iPrimaryMedia),LOCM_FAULT()); // valid drive number?
m.Drive()=pL;
#ifdef __DEMAND_PAGING_BENCHMARKS__
__e32_atomic_add_ord32(&iMediaPagingInfo.iCodePageInCount, (TUint) 1);
info = &iCodeBenchmarkData;
#endif
}
else
LOCM_FAULT(); // invalid drive number
m.RemoteThread()=NULL;
m.Pos()=offset;
m.Length()=Int64(size);
m.RemoteDes()=(TAny*)aBuffer;
m.RemoteDesOffset()=0; // pre-aligned
m.DriverFlags()=0;
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("ReqId=%d, Pos=0x%lx, Len=0x%lx, remote Des 0x%x",m.Id(),m.Pos(),m.Length(),m.RemoteDes()));
OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DMEDIAPAGINGDEVICE_READ2, "reqId=%d; position=0x%lx; length=0x%x; remote Des=0x%x", (TInt) m.Id(), (TUint) m.Pos(), (TUint) m.Length(), (TUint) m.RemoteDes());
__ASSERT_DEBUG(iPrimaryMedia->iBody, LOCM_FAULT());
TInt mediaChanges = iPrimaryMedia->iBody->iMediaChanges;
SendToMainQueueDfcAndBlock(&m); // queues request, sets and opens client thread, queues dfc and blocks thread until request is completed
retVal = m.iValue;
#ifdef __DEBUG_DEMAND_PAGING__
if (retVal != KErrNone)
{
Kern::Printf("Pagin Failure %d, retry %d", retVal, i);
}
#endif
// reset retry count if there's ben a media change
if (retVal != KErrNone && mediaChanges != iPrimaryMedia->iBody->iMediaChanges)
i = 0;
} // for ()
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
NKern::FMWait(&iInstrumentationLock);
if (*servicingCount)
(*servicingCount)--;
NKern::FMSignal(&iInstrumentationLock);
#endif
#ifdef __DEMAND_PAGING_BENCHMARKS__
TUint32 bmEnd = NKern::FastCounter();
++info->iCount;
#if !defined(HIGHIGH_RES_TIMER) || defined(HIGH_RES_TIMER_COUNTS_UP)
TInt64 elapsed=bmEnd-bmStart;
#else
TInt64 elapsed=bmStart-bmEnd;
#endif
info->iTotalTime += elapsed;
if (elapsed > info->iMaxTime)
info->iMaxTime = elapsed;
if (elapsed < info->iMinTime)
info->iMinTime = elapsed;
#endif // __DEMAND_PAGING_BENCHMARKS__
OstTraceFunctionExitExt( DMEDIAPAGINGDEVICE_READ_EXIT2, this, retVal );
return retVal;
}
TInt DMediaPagingDevice::Write(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TBool aBackground)
{
OstTraceFunctionEntry1( DMEDIAPAGINGDEVICE_WRITE_ENTRY, this );
__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT()); // that would lock up the system, thus better die now
__ASSERT_ALWAYS(aReq,LOCM_FAULT());
__ASSERT_CRITICAL
#ifdef __DEMAND_PAGING_BENCHMARKS__
TUint32 bmStart = NKern::FastCounter();
#endif
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
NKern::FMWait(&iInstrumentationLock);
if(iServicingDataOut)
iDataStats.iTotalConcurrentReqs++;
if(!(++iServicingDataOut))
{
iServicingDataOut=1; // overflow...
iDataStats.iTotalConcurrentReqs=0; // ...reset this
}
TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
if(!empty)
iDataStats.iTotalReqIssuedNonEmptyQ++;
NKern::FMSignal(&iInstrumentationLock);
#endif
TUint offset=aOffset<<iReadUnitShift;
TUint size=aSize<<iReadUnitShift;
#ifdef BTRACE_PAGING_MEDIA
TInt buf[2];
buf[0] = size; // page out request length
buf[1] = (TInt)aReq; // address of request object
BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageOutBegin,aBuffer,offset,buf,sizeof(buf));
#endif
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::Write, Req(0x%08x), Buff(0x%x),Offset(%d),Size(%d)",aReq,aBuffer,offset,size));
OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DMEDIAPAGINGDEVICE_WRITE1, "req=0x%08x; aBuffer=0x%x; offset=%d; size=%d", (TUint) aReq, (TUint) aBuffer, offset, size);
// no DFCQ, media driver executes in the context of calling thread
if (!iPrimaryMedia->iDfcQ)
{
LOCM_FAULT(); // don't allow paging
OstTraceFunctionExitExt( DMEDIAPAGINGDEVICE_WRITE_EXIT, this, KErrNone );
return KErrNone; // keep compiler happy
}
TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
#ifdef __DEMAND_PAGING_BENCHMARKS__
__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageOutCount, (TUint) 1);
if (aBackground)
__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageOutBackgroundCount, (TUint) 1);
#endif
// Write to the media and allow for retries in the unlikely event of an error.
const TInt KPageOutRetries = 5;
TInt retVal = KErrGeneral;
for (TInt i=0; retVal != KErrNone && i < KPageOutRetries; i++)
{
m.Flags() = TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging | (aBackground ? TLocDrvRequest::EBackgroundPaging : 0);
m.Id() = DLocalDrive::EWrite;
m.Drive() = TheDrives[iDataPagingDriveNumber];
m.RemoteThread()=NULL;
m.Pos()=offset;
m.Length()=Int64(size);
m.RemoteDes()=(TAny*)aBuffer;
m.RemoteDesOffset()=0; // pre-aligned
m.DriverFlags()=0;
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("ReqId=%d, Pos=0x%lx, Len=0x%lx, remote Des 0x%x",m.Id(),m.Pos(),m.Length(),m.RemoteDes()));
OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DMEDIAPAGINGDEVICE_WRITE2, "reqId=%d; position=0x%lx; length=0x%lx; remote Des=0x%x", (TInt) m.Id(), (TUint) m.Pos(), (TUint) m.Length(), (TUint) m.RemoteDes());
__ASSERT_DEBUG(iPrimaryMedia->iBody, LOCM_FAULT());
TInt mediaChanges = iPrimaryMedia->iBody->iMediaChanges;
SendToMainQueueDfcAndBlock(&m); // queues request, sets and opens client thread, queues dfc and blocks thread until request is completed
retVal = m.iValue;
#ifdef __DEBUG_DEMAND_PAGING__
if (retVal != KErrNone)
Kern::Printf("Pagout Failure %d, retry %d", retVal, i);
#endif
// reset retry count if there's ben a media change
if (retVal != KErrNone && mediaChanges != iPrimaryMedia->iBody->iMediaChanges)
i = 0;
} // for ()
#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
NKern::FMWait(&iInstrumentationLock);
if (iServicingDataOut)
iServicingDataOut--;
NKern::FMSignal(&iInstrumentationLock);
#endif
#ifdef __DEMAND_PAGING_BENCHMARKS__
SPagingBenchmarkInfo& info = iDataOutBenchmarkData;
TUint32 bmEnd = NKern::FastCounter();
++info.iCount;
#if !defined(HIGHIGH_RES_TIMER) || defined(HIGH_RES_TIMER_COUNTS_UP)
TInt64 elapsed=bmEnd-bmStart;
#else
TInt64 elapsed=bmStart-bmEnd;
#endif
info.iTotalTime += elapsed;
if (elapsed > info.iMaxTime)
info.iMaxTime = elapsed;
if (elapsed < info.iMinTime)
info.iMinTime = elapsed;
#endif // __DEMAND_PAGING_BENCHMARKS__
OstTraceFunctionExitExt( DMEDIAPAGINGDEVICE_WRITE_EXIT2, this, retVal );
return retVal;
}
TInt DMediaPagingDevice::DeleteNotify(TThreadMessage* aReq,TUint aOffset,TUint aSize)
{
OstTraceFunctionEntry1( DMEDIAPAGINGDEVICE_DELETENOTIFY_ENTRY, this );
if (iDeleteNotifyNotSupported)
{
OstTraceFunctionExitExt( DMEDIAPAGINGDEVICE_DELETENOTIFY_EXIT1, this, KErrNotSupported );
return KErrNotSupported;
}
__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT()); // that would lock up the system, thus better die now
__ASSERT_ALWAYS(aReq,LOCM_FAULT());
__ASSERT_ALWAYS(DataPagingDfcQ(iPrimaryMedia),LOCM_FAULT());
__ASSERT_CRITICAL
TUint offset = aOffset<<iReadUnitShift;
TUint size = aSize<<iReadUnitShift;
#ifdef BTRACE_PAGING_MEDIA
TInt buf[2];
buf[0] = size; // delete notify length
buf[1] = (TInt)aReq; // address of request object
BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedDeleteNotifyBegin,NULL,offset,buf,sizeof(buf));
#endif
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::Write, Req(0x%08x), Offset(%d),Size(%d)",aReq,offset,size));
OstTraceDefExt3(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DMEDIAPAGINGDEVICE_DELETENOTIFY1 , "req=0x%08x; offset=%d; size=%d", (TUint) aReq, offset, size);
// no DFCQ, media driver executes in the context of calling thread
if (!iPrimaryMedia->iDfcQ)
{
LOCM_FAULT(); // don't allow paging
OstTraceFunctionExitExt( DMEDIAPAGINGDEVICE_DELETENOTIFY_EXIT2, this, KErrNone );
return KErrNone; // keep compiler happy
}
TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
m.Flags() = TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging;
m.Id() = DLocalDrive::EDeleteNotify;
m.Drive() = TheDrives[iDataPagingDriveNumber];
m.RemoteThread() = NULL;
m.Pos() = offset;
m.Length() = Int64(size);
m.RemoteDes() = NULL;
m.RemoteDesOffset() = 0; // pre-aligned
m.DriverFlags()=0;
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("ReqId=%d, Pos=0x%lx, Len=0x%lx, remote Des 0x%x",m.Id(),m.Pos(),m.Length(),m.RemoteDes()));
OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DMEDIAPAGINGDEVICE_DELETENOTIFY2 , "reqId=%d; position=0x%lx; length=0x%lx; remote Des=0x%x", m.Id(), m.Pos(), m.Length(), (TUint) m.RemoteDes());
// send request aynchronously as we don't particularly care about the result
// and waiting would slow down the thread taking the page fault
iPrimaryMedia->RequestCountInc();
m.SendReceive(&iMainQ); // send request synchronously
#ifdef __DEMAND_PAGING__
iPrimaryMedia->RequestCountDec();
#endif
TInt retVal = m.iValue;
if (retVal == KErrNotSupported)
iDeleteNotifyNotSupported = ETrue;
OstTraceFunctionExitExt( DMEDIAPAGINGDEVICE_DELETENOTIFY_EXIT3, this, retVal );
return retVal;
}
EXPORT_C TInt TLocDrvRequest::WriteToPageHandler(const TAny* aSrc, TInt aSize, TInt anOffset)
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_WRITETOPAGEHANDLER_ENTRY, this );
#ifdef BTRACE_PAGING_MEDIA
TMediaDevice medDev=Drive()->iMedia->iDevice;
TInt buf[3];
buf[0]=(TUint32)RemoteDes();
buf[1]=anOffset;
buf[2]=aSize;
BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaMedDrvWriteBack,medDev,this,buf,sizeof(buf));
#endif
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("TLocDrvRequest::WriteToPageHandler, memcpy((aTrg)%08x, (aSrc)%08x, (aLength)%08x)",(TUint32)RemoteDes()+anOffset,aSrc,aSize));
(void)memcpy((TAny*)((TUint32)RemoteDes()+anOffset), aSrc, aSize); // maybe in later versions this could be something else
OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITETOPAGEHANDLER_EXIT, this, KErrNone );
return KErrNone;
}
EXPORT_C TInt TLocDrvRequest::ReadFromPageHandler(TAny* aDst, TInt aSize, TInt anOffset)
{
OstTraceFunctionEntry1( TLOCDRVREQUEST_READFROMPAGEHANDLER_ENTRY, this );
#ifdef BTRACE_PAGING_MEDIA
TMediaDevice medDev=Drive()->iMedia->iDevice;
TInt buf[3];
buf[0]=(TUint32)RemoteDes();
buf[1]=anOffset;
buf[2]=aSize;
BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaMedDrvRead,medDev,this,buf,sizeof(buf));
#endif
__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("TLocDrvRequest::ReadFromPageHandler, memcpy((aDst)%08x, (aTrg)%08x, (aLength)%08x)",aDst,(TUint32)RemoteDes()+anOffset,aSize));
(void)memcpy(aDst, (TAny*)((TUint32)RemoteDes()+anOffset), aSize); // maybe in later versions this could be something else
OstTraceFunctionExitExt( TLOCDRVREQUEST_READFROMPAGEHANDLER_EXIT, this, KErrNone );
return KErrNone;
}
_LIT(KLitFragmentationMutexName, "FRAGMENTATION_MUTEX");
TInt DFragmentationPagingLock::Construct(TUint aNumPages)
{
OstTraceFunctionEntryExt( DFRAGMENTATIONPAGINGLOCK_CONSTRUCT_ENTRY, this );
TInt r=KErrNone;
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation Lock: creating Mutex"));
r=Kern::MutexCreate(this->iFragmentationMutex, KLitFragmentationMutexName, KMutexOrdNone);
if (r!=KErrNone)
{
OstTraceFunctionExitExt( DFRAGMENTATIONPAGINGLOCK_CONSTRUCT_EXIT1, this, r );
return r;
}
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation Lock: Mutex created OK"));
OstTraceDef0(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DFRAGMENTATIONPAGINGLOCK_CONSTRUCT1 , "Fragmentation Lock: Mutex created OK");
iFragmentGranularity = 0;
if (aNumPages == 0)
{
OstTraceFunctionExitExt( DFRAGMENTATIONPAGINGLOCK_CONSTRUCT_EXIT2, this, KErrNone );
return KErrNone;
}
// in CS
TInt pageSize=Kern::RoundToPageSize(1);
LockFragmentation();
r=Alloc(pageSize*aNumPages); // alloc pages
UnlockFragmentation();
if(r==KErrNone)
{
iFragmentGranularity = pageSize * aNumPages;
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation granularity set to 0x%x", iFragmentGranularity));
OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DFRAGMENTATIONPAGINGLOCK_CONSTRUCT2, "Fragmentation granularity=0x%x", iFragmentGranularity);
}
OstTraceFunctionExitExt( DFRAGMENTATIONPAGINGLOCK_CONSTRUCT_EXIT3, this, r );
return r;
}
void DFragmentationPagingLock::Cleanup()
{
OstTraceFunctionEntry1( DFRAGMENTATIONPAGINGLOCK_CLEANUP_ENTRY, this );
// in CS
if (iFragmentationMutex)
{
LockFragmentation();
Free(); // at last!
UnlockFragmentation();
Kern::SafeClose((DObject*&)iFragmentationMutex,NULL);
}
OstTraceFunctionExit1( DFRAGMENTATIONPAGINGLOCK_CLEANUP_EXIT, this );
}
#else
#if !defined(__WINS__)
EXPORT_C TInt TLocDrvRequest::WriteToPageHandler(const TAny* , TInt , TInt)
{
return KErrNone; // stub for def file
}
#endif // __WINS__
#endif //__DEMAND_PAGING__
/********************************************
* Media driver base class
********************************************/
/**
Constructor.
This is called, typically, by a derived class constructor in its ctor list.
@param aMediaId The value of the unique media ID assigned when the media
driver is registered.
@see LocDrv::RegisterMediaDevice()
*/
EXPORT_C DMediaDriver::DMediaDriver(TInt aMediaId)
{
OstTraceFunctionEntryExt( DMEDIADRIVER_DMEDIADRIVER_ENTRY, this );
// iPhysicalDevice=NULL;
// iTotalSizeInBytes=0;
// iCurrentConsumption=0;
// iPrimaryMedia=NULL;
// iCritical=EFalse;
iPrimaryMedia=(DPrimaryMediaBase*)TheMedia[aMediaId];
OstTraceFunctionExit1( DMEDIADRIVER_DMEDIADRIVER_EXIT, this );
}
/**
Destructor.
Sets the device's current consumption to zero, and calls Close() on
the PDD factory object.
@see DObject::Close()
*/
EXPORT_C DMediaDriver::~DMediaDriver()
{
OstTraceFunctionEntry1( DMEDIADRIVER_DMEDIADRIVER_DESTRUCTOR_ENTRY, this );
SetCurrentConsumption(0);
Kern::SafeClose((DObject*&)iPhysicalDevice,NULL);
OstTraceFunctionExit1( DMEDIADRIVER_DMEDIADRIVER_DESTRUCTOR_EXIT, this );
}
/**
Closes the media driver.
This default implementation simply deletes this DMediaDriver object.
Media drivers can provide their own implementation, which gives them
the opportunity to clean up resources before closure; for example,
cancelling a DFC.
Any replacement function must call this base class function as
the last instruction.
*/
EXPORT_C void DMediaDriver::Close()
{
delete this;
}
/**
Sets the total size of the media device.
The function must be called by the media driver's implementation of PartitionInfo().
@param aTotalSizeInBytes The total size of the media, in bytes.
@param aLocDrv This is not used by media drivers; the class
definition provides a default value.
@see DMediaDriver::PartitionInfo()
*/
EXPORT_C void DMediaDriver::SetTotalSizeInBytes(Int64 aTotalSizeInBytes, TLocDrv* aLocDrv)
{
OstTraceFunctionEntry1( DMEDIADRIVER_SETTOTALSIZEINBYTES_ENTRY, this );
iTotalSizeInBytes=aTotalSizeInBytes;
if (aLocDrv)
aLocDrv->iPartitionLen=aTotalSizeInBytes;
OstTraceFunctionExit1( DMEDIADRIVER_SETTOTALSIZEINBYTES_EXIT, this );
}
/**
Gets the total size of the media.
@return The total size of the media, in bytes.
@see DMediaDriver::SetTotalSizeInBytes()
*/
EXPORT_C Int64 DMediaDriver::TotalSizeInBytes()
{
return iTotalSizeInBytes;
}
/**
Flags the media driver as entering a critical part of its processing.
In this context, critical means that the driver must be allowed to complete
its current activity.
For example, a request to power down the device must be deferred until
the driver exits the critical part.
@return KErrNone, if the driver has been successfully flagged as being in
a critical part; otherwise, one of the other system-wide error codes.
@see DMediaDriver::EndInCritical()
*/
EXPORT_C TInt DMediaDriver::InCritical()
{
OstTraceFunctionEntry1( DMEDIADRIVER_INCRITICAL_ENTRY, this );
if (!iCritical)
{
TInt r=iPrimaryMedia->InCritical();
if (r!=KErrNone)
{
OstTraceFunctionExitExt( DMEDIADRIVER_INCRITICAL_EXIT, this, r );
return r;
}
iCritical=ETrue;
}
OstTraceFunctionExitExt( DMEDIADRIVER_INCRITICAL_EXIT2, this, KErrNone );
return KErrNone;
}
/**
Flags the media driver as leaving a critical part of its processing.
@see DMediaDriver::InCritical()
*/
EXPORT_C void DMediaDriver::EndInCritical()
{
OstTraceFunctionEntry1( DMEDIADRIVER_ENDINCRITICAL_ENTRY, this );
if (iCritical)
{
iCritical=EFalse;
iPrimaryMedia->EndInCritical();
}
OstTraceFunctionExit1( DMEDIADRIVER_ENDINCRITICAL_EXIT, this );
}
/**
@internalComponent
*/
EXPORT_C void DMediaDriver::SetCurrentConsumption(TInt aValue)
{
OstTraceFunctionEntryExt( DMEDIADRIVER_SETCURRENTCONSUMPTION_ENTRY, this );
TInt old = (TInt)__e32_atomic_swp_ord32(&iCurrentConsumption, aValue);
TInt delta = aValue - old;
iPrimaryMedia->DeltaCurrentConsumption(delta);
OstTraceFunctionExit1( DMEDIADRIVER_SETCURRENTCONSUMPTION_EXIT, this );
}
/**
Informs the media driver subsystem that an asynchronous request is complete.
@param m The request that this call is completing.
@param aResult The return code for the asynchronous request. Typically, this
is KErrNone to report success, or one of the other system-wide
error codes to report failure or other problems.
*/
EXPORT_C void DMediaDriver::Complete(TLocDrvRequest& m, TInt aResult)
{
OstTraceExt2( TRACE_FLOW, DMEDIADRIVER_COMPLETE_ENTRY, "m=%x;aResult=%d", (TUint) &m, aResult );
CHECK_RET(aResult);
#ifdef __DEMAND_PAGING__
if (DMediaPagingDevice::PagingRequest(m))
{
__ASSERT_ALWAYS(iPrimaryMedia && iPrimaryMedia->iPagingMedia && iPrimaryMedia->iBody->iPagingDevice,LOCM_FAULT());
__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
DMediaPagingDevice* pagingdevice = iPrimaryMedia->iBody->iPagingDevice;
pagingdevice->CompleteRequest(&m, aResult);
}
else
#endif
iPrimaryMedia->CompleteRequest(m, aResult);
if (&m == iPrimaryMedia->iCurrentReq) // Complete() called on request serviced synchronously
iPrimaryMedia->iCurrentReq = NULL;
iPrimaryMedia->RunDeferred();
OstTraceFunctionExit1( DMEDIADRIVER_COMPLETE_EXIT, this );
}
/**
Informs the media driver subsystem that the media driver is open
and has been initialised.
This can be called from the PDD factory function Create(), if opening and
initialising the media driver is synchronous, otherwise it should be called by
the asynchronous media driver function that is responsible for opening and
initialising the driver.
@param anError KErrNone if successful, otherwise one of the other system wide
error codes.
*/
EXPORT_C void DMediaDriver::OpenMediaDriverComplete(TInt anError)
{
OstTraceFunctionEntry1( DMEDIADRIVER_OPENMEDIADRIVERCOMPLETE_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DMediaDriver::OpenMediaDriverComplete(%d) this %x iPrimaryMedia %x", anError, this, iPrimaryMedia));
OstTraceDefExt3(OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DMEDIADRIVER_OPENMEDIADRIVERCOMPLETE, "anError %d this 0x%x iPrimaryMedia 0x%x", anError, (TUint) this, (TUint) iPrimaryMedia);
DPrimaryMediaBase* pM=iPrimaryMedia;
pM->iAsyncErrorCode=anError;
pM->iAsyncDfc.Enque();
OstTraceFunctionExit1( DMEDIADRIVER_OPENMEDIADRIVERCOMPLETE_EXIT, this );
}
/**
Informs the media driver subsystem that the media driver has completed
the provision of partition information.
The media driver provides partition information in its implementation
of PartitionInfo().
@param anError KErrNone if successful, otherwise one of the other system wide
error codes.
@see DMediaDriver::PartitionInfo()
*/
EXPORT_C void DMediaDriver::PartitionInfoComplete(TInt anError)
{
OstTraceFunctionEntry1( DMEDIADRIVER_PARTITIONINFOCOMPLETE_ENTRY, this );
__KTRACE_OPT(KLOCDRV,Kern::Printf("DMediaDriver::PartitionInfoComplete(%d) anError %d this %x iPrimaryMedia %x", anError, this, iPrimaryMedia));
OstTraceExt3( TRACE_INTERNALS, DMDEDIADRIVER_PARTITIONINFOCOMPLETE, "anError=%d; this=%x; iPrimaryMedia=%x", anError, (TUint) this, (TUint) iPrimaryMedia );
DPrimaryMediaBase* pM=iPrimaryMedia;
pM->iAsyncErrorCode=anError;
pM->iAsyncDfc.Enque();
OstTraceFunctionExit1( DMEDIADRIVER_PARTITIONINFOCOMPLETE_EXIT, this );
}
/**
@internalComponent
*/
// Default implementation
EXPORT_C void DMediaDriver::Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg)
{
OstTraceFunctionEntryExt( DMEDIADRIVER_DISCONNECT_ENTRY, this );
// don't need to worry about DLocalDrive going away
aLocalDrive->Deque();
aMsg->Complete(KErrNone, EFalse);
OstTraceFunctionExit1( DMEDIADRIVER_DISCONNECT_EXIT, this );
}
/**
Registers a media driver with the Local Media Subsystem, and provides
information about the number of supported drives, partitions,
names and drive numbers.
@param aDevice The unique Media ID for this device.
This can take one of the enumerated values defined
by the TMediaDevice enum.
@param aDriveCount Specifies the number of local drive objects to be assigned
to the media driver. Drives that support more than one
partition must specify a number greater than 1.
@param aDriveList A pointer to an array of TInt values, which define
the drive numbers that are to be allocated to each partition.
0 signifies Drive C, 1 signifies drive D, etc. For example,
to allocate drive letters J and K, specify an array
containing the values [7,8].
Note that the size of this array must be the same as the value
specified by aDriveCount.
@param aPrimaryMedia A pointer to the primary DPrimaryMedia object to be
associated with the media. This object is responsible for
the overall state of the media, i.e. powering up, reading
partition information etc. It also has overall control over
all partitions as represented by the additional (aNumMedia-1)
DMedia objects.
@param aNumMedia Specifies the total number of DMedia objects to be
associated with the media driver. This number includes the
primary DPrimaryMedia object referred to by aPrimaryMedia,
plus all of the DMedia objects that are created for each
additional drive, and which hold basic information about
partitions.
@param aName The name of the media driver, for example: PCCard
@return KErrNone, if successful;
KErrInUse, if a drive is already in use;
KErrNoMemory, if there is insufficient memory;
or one of the other system-wide error codes.
*/
EXPORT_C TInt LocDrv::RegisterMediaDevice(TMediaDevice aDevice, TInt aDriveCount, const TInt* aDriveList, DPrimaryMediaBase* aPrimaryMedia, TInt aNumMedia, const TDesC& aName)
{
OstTraceFunctionEntry0( LOCDRV_REGISTERMEDIADEVICE_ENTRY );
// Create TLocDrv / DMedia objects to handle a media device
__KTRACE_OPT(KBOOT,Kern::Printf("RegisterMediaDevice %lS dev=%1d #drives=%d 1st=%d PM=%08x #media=%d",&aName,aDevice,aDriveCount,*aDriveList,aPrimaryMedia,aNumMedia));
OstTraceExt5( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE1, "aDevice=%d; aDriveCount=%d; aDriveList=%d; aPrimaryMedia=0x%08x; aNumMedia=%d", (TInt) aDevice, (TInt) aDriveCount, (TInt) *aDriveList, (TUint) aPrimaryMedia, (TInt) aNumMedia );
const TInt* p=aDriveList;
TInt i;
TInt r=0;
if (UsedMedia+aNumMedia>KMaxLocalDrives)
{
OstTrace0(TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT1, "< KErrInUse");
return KErrInUse;
}
for (i=0; i<aDriveCount; ++i)
{
TInt drv = *p++;
// -1 means not used; this is to enable Dual-slot MMC support
if (drv == -1)
continue;
__KTRACE_OPT(KBOOT,Kern::Printf("Registering drive %d", drv));
OstTrace1( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE2, "Registering drive=%d", drv );
if (TheDrives[drv])
{
__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d already in use", drv));
OstTrace1( TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT2, "< Drive %d already in use; KErrInUse", drv);
return KErrInUse;
}
}
HBuf* pN=HBuf::New(aName);
if (!pN)
{
OstTrace0(TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT3, "< KErrNoMemory");
return KErrNoMemory;
}
TInt lastMedia=UsedMedia+aNumMedia-1;
for (i=UsedMedia; i<=lastMedia; ++i)
{
if (i==UsedMedia)
TheMedia[i]=aPrimaryMedia;
else
TheMedia[i]=new DMedia;
if (!TheMedia[i])
{
OstTrace0(TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT4, "< KErrNoMemory");
return KErrNoMemory;
}
r=TheMedia[i]->Create(aDevice,i,lastMedia);
__KTRACE_OPT(KBOOT,Kern::Printf("Media %d Create() returns %d",i,r));
OstTraceExt2( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE3, "Media=%d Create(); retval=%d", i, r );
if (r!=KErrNone)
{
OstTrace1(TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT5, "< retval=%d", r);
return r;
}
}
__KTRACE_OPT(KBOOT,Kern::Printf("FirstMedia %d LastMedia %d",UsedMedia,lastMedia));
OstTraceExt2( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE4, "FirstMedia=%d; LastMedia=%d", UsedMedia, lastMedia );
UsedMedia+=aNumMedia;
p=aDriveList;
for (i=0; i<aDriveCount; ++i)
{
TInt drv=*p++;
if (drv == -1)
continue;
TLocDrv* pL=new TLocDrv(drv);
if (!pL)
{
OstTrace0(TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT6, "< KErrNoMemory");
return KErrNoMemory;
}
TheDrives[drv]=pL;
DriveNames[drv]=pN;
pL->iPrimaryMedia=aPrimaryMedia;
__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d: TLocDrv @ %08x",drv,pL));
OstTraceExt2( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE5, "Drive=%d; TLocDrv 0x%08x;", (TInt) drv, (TUint) pL );
}
OstTraceFunctionExit0( LOCDRV_REGISTERMEDIADEVICE_EXIT7 );
return KErrNone;
}
/**
A utility function that is used internally to register the specified
password store.
The password store is used to save passwords for local media.
@param aStore A pointer to the password store to be registered.
@return KErrNone, if successful;
KErrAlreadyExists, if a password store has already been registered.
*/
EXPORT_C TInt LocDrv::RegisterPasswordStore(TPasswordStore* aStore)
{
OstTraceFunctionEntry0( LOCDRV_REGISTERPASSWORDSTORE_ENTRY );
// Create TLocDrv / DMedia objects to handle a media device
__KTRACE_OPT(KBOOT,Kern::Printf("RegisterPasswordStore"));
TInt r = KErrNone;
if(ThePasswordStore == NULL)
ThePasswordStore = aStore;
else
r = KErrAlreadyExists;
OstTrace1(TRACE_INTERNALS, LOCDRV_REGISTERPASSWORDSTORE, "retval=%d", r);
OstTraceFunctionExit0( LOCDRV_REGISTERPASSWORDSTORE_EXIT );
return r;
}
/**
Returns a pointer to the registered password store.
The password store is used to save passwords for local media.
@return A pointer to the registered password store.
*/
EXPORT_C TPasswordStore* LocDrv::PasswordStore()
{
return ThePasswordStore;
}
#ifdef __DEMAND_PAGING__
/**
Registers a paging device with the Local Media Subsystem, and provides
information about drive numbers used in Code Paging.
@param aPrimaryMedia A pointer to the primary DPrimaryMedia object associated
with the media.
@param aPagingDriveList A pointer to an array of TInt values, which define
the drive numbers used as Code backup in Code Paging, which
are the target of Page In requests. For NAND these will
will be usually associated with ROFS and/or User Data drives.
In ROM pagigng systems no drive is specified, it is assumed
a fixed media for which no non-primary media exists, will be
used.
@param aDriveCount Specifies the number of local drives associated with this
media device which can be used for code paging.
@param aPagingType Identifies the type of Paging this media device is capable
of servicing.
@param aReadShift Log2 of the read unit size. A read unit is the number of bytes
which the device can optimally read from the underlying media.
E.g. for small block NAND, a read unit would be equal to the
page size, 512 bytes, therefore iReadShift would be set to 9.
@param aNumPages The number of pages to alloc for each drive associated with this
media driver. The pages are used in request fragmentation.
@return KErrNone, if successful;
KErrNotFound, if at least one of the drive numbers
specified has not yet been mapped.
KErrArgument, if the passed in an invalid argument.
KErrNotSupported, if at least one of the drive numbers
specifed is not associated with this Primary Media.
KErrNoMemory, if there is insufficient memory;
or one of the other system-wide error codes.
*/
EXPORT_C TInt LocDrv::RegisterPagingDevice(DPrimaryMediaBase* aPrimaryMedia, const TInt* aPagingDriveList, TInt aDriveCount, TUint aPagingType, TInt aReadShift, TUint aNumPages)
{
OstTraceFunctionEntry0( LOCDRV_REGISTERPAGINGDEVICE_ENTRY );
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf(">RegisterPagingDevice: paging type=%d PM=0x%x read shift=%d",aPagingType,aPrimaryMedia,aReadShift));
OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE1, "aPagingType=%d; aPrimaryMedia=0x%x; aReadShift=%d", (TInt) aPagingType, (TUint) aPrimaryMedia, (TInt) aReadShift);
TInt i;
if(!aPagingType || (aPagingType&~(DPagingDevice::ERom | DPagingDevice::ECode | DPagingDevice::EData)))
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Unsupported paging type, exiting"));
OstTrace0(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT1, "< Unsupported paging type; KErrArgument");
return KErrArgument;
}
for(i=0; i<KMaxLocalDrives; i++)
{
if (ThePagingDevices[i] == NULL)
continue;
if ((ThePagingDevices[i]->iType&DPagingDevice::ERom) && (aPagingType & DPagingDevice::ERom))
{
aPagingType&=~DPagingDevice::ERom; // already have a ROM paging device
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Already has ROM pager on locdrv no %d",i));
}
if ((ThePagingDevices[i]->iType&DPagingDevice::EData) && (aPagingType & DPagingDevice::EData))
{
aPagingType&=~DPagingDevice::EData; // already have a Data paging device
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Already has Data pager on locdrv no %d",i));
}
}
if (aPagingType == 0)
{
// there's already a ROM or Data paging device & this doesn't support code paging so quietly exit without further addo
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Nothing left to register on locdrv no %d, exiting",i));
OstTrace1(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT2, "< Nothing left to register on locdrv no %d; KErrNone",i);
return KErrNone;
}
const TInt* p=aPagingDriveList;
if(aPagingType&DPagingDevice::ECode) // supports code paging, do argument check
{
if(!aDriveCount || (aDriveCount>=KMaxLocalDrives))
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive count: %d", aDriveCount));
OstTrace1(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT3, "< Invalid code paging drive count=%d; KErrArgument", aDriveCount);
return KErrArgument;
}
TInt drvCount=0;
for(i=0; i<KMaxLocalDrives; i++)
if(TheDrives[i] && TheDrives[i]->iPrimaryMedia==aPrimaryMedia)
drvCount++;
if(aDriveCount>drvCount) // can't exceed number of drives registered by this device
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive count=%d; total=%d", aDriveCount, drvCount));
OstTraceExt2(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT4, "< Invalid code paging drive count=%d; total=%d; KErrArgument", aDriveCount, drvCount);
return KErrArgument;
}
for (i=0; i<aDriveCount; ++i)
{
__KTRACE_OPT(KBOOT,Kern::Printf("RegisterPagingDevice: registering drive=%d ",*p));
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE2, "Registering Drive=%d", *p );
TInt drv=*p++;
if(drv>=KMaxLocalDrives)
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive number: %d", drv));
OstTrace1(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT5, "< Invalid code paging drive number=%d; KErrArgument", drv);
return KErrArgument;
}
TLocDrv* pD=TheDrives[drv];
if (!pD)
{
OstTrace0(TRACE_FLOW, LOCRV_REGISTERPAGINGDEVICE_EXIT6, "< KErrNotFound");
return KErrNotFound;
}
if (pD->iPrimaryMedia!=aPrimaryMedia)
{
OstTrace0(TRACE_FLOW, LOCRV_REGISTERPAGINGDEVICE_EXIT7, "< KErrNotSupported");
return KErrNotSupported;
}
}
}
TInt firstLocalDriveNumber = KErrNotFound;
TInt romPagingDriveNumber = KErrNotFound;
TInt dataPagingDriveNumber = KErrNotFound;
TInt swapSize = 0;
// find the local drive assocated with the primary media
for (i=0; i<KMaxLocalDrives; ++i)
{
if(TheDrives[i] && TheDrives[i]->iPrimaryMedia == aPrimaryMedia)
{
firstLocalDriveNumber = i;
break;
}
}
__ASSERT_ALWAYS(i < KMaxLocalDrives, LOCM_FAULT());
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("DMediaPagingDevice(), firstLocalDriveNumber %d", firstLocalDriveNumber));
OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE3, "firstLocalDriveNumber=%d", firstLocalDriveNumber );
// Send an ECaps message to wake up the media driver & ensure all partitions are
// reported, then search for paged-data or paged-ROM partitions
if ((aPagingType & DPagingDevice::EData) ||
(aPagingType & DPagingDevice::ERom && aPrimaryMedia->iDfcQ && aPrimaryMedia->iMsgQ.iReady))
{
// the message queue must have been started already (by the media driver calling iMsgQ.Receive())
// otherwise we can't send the DLocalDrive::EQueryDevice request
if (aPrimaryMedia->iDfcQ && !aPrimaryMedia->iMsgQ.iReady)
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: Message queue not started"));
OstTrace0(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT8, "< RegisterPagingDevice: Message queue not started; KErrNotReady");
return KErrNotReady;
}
TLocDrvRequest m;
memclr(&m, sizeof(m));
// Get the Caps from the device. NB for MMC/SD we may need to retry as some PSLs start up
// in "door open" or "media not present" state which can result in the cancellation of requests
TInt i;
const TInt KRetries = 5;
TInt r = KErrNotReady;
for (i=0; r == KErrNotReady && i < KRetries; i++)
{
TBuf8<KMaxLocalDriveCapsLength> capsBuf;
capsBuf.SetMax();
capsBuf.FillZ();
m.Drive() = TheDrives[firstLocalDriveNumber];
m.Id() = DLocalDrive::ECaps;
m.RemoteDes() = (TAny*)capsBuf.Ptr(); // overload this
m.Length() = KMaxLocalDriveCapsLength; // for pinning
r = aPrimaryMedia->Request(m);
//Kern::Printf("EQueryPageDeviceInfo: i %d: r %d ", i, r);
__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Paging device ECaps: i %d: r %d ", i, r));
OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE4, "Paging device ECaps: i %d retval=%d", i, r);
}
if (r != KErrNone)
{
OstTrace1(TRACE_FLOW, LOCRV_REGISTERPAGINGDEVICE_EXIT9, "< retval=%d",r);
return r;
}
TLocDrv* drive;
for (i=0; i<KMaxLocalDrives; ++i)
{
drive = TheDrives[i];
if(drive && drive->iPrimaryMedia == aPrimaryMedia)
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("RegisterPagingDevice: local drive %d, partition type %x size %x", i, drive->iPartitionType, I64LOW(drive->iPartitionLen)));
// ROM partition ?
if ((romPagingDriveNumber == KErrNotFound) && (drive->iPartitionType == KPartitionTypeROM))
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Found ROM partition on local drive %d, size %x", i, I64LOW(drive->iPartitionLen)));
OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE5, "Found ROM partition on local drive=%d; size=0x%x", (TInt) i, (TUint) I64LOW(drive->iPartitionLen));
romPagingDriveNumber = i;
}
// swap partition ?
else if ((dataPagingDriveNumber == KErrNotFound) && (drive->iPartitionType == KPartitionTypePagedData))
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Found swap partition on local drive %d, size %x", i, I64LOW(drive->iPartitionLen)));
OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE6, "Found SWAP partition on local drive=%d; size=0x%x", (TInt) i, (TUint) I64LOW(drive->iPartitionLen) );
dataPagingDriveNumber = i;
swapSize = drive->iPartitionLen >> aReadShift;
}
}
}
if (swapSize == 0)
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Disabling data paging"));
OstTraceDef0(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE7, "Disabling data paging");
aPagingType &= ~DPagingDevice::EData;
}
}
// create and set up a DPagingDevice to allow PageIn request servicing
DMediaPagingDevice* pagingDevice = new DMediaPagingDevice(aPrimaryMedia);
if(!pagingDevice)
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not create paging device"));
OstTrace0(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT_EXIT10, "< RegisterPagingDevice: could not create paging device; KErrNoMemory");
return KErrNoMemory;
}
pagingDevice->iType = aPagingType;
pagingDevice->iReadUnitShift = aReadShift;
pagingDevice->iFirstLocalDriveNumber = firstLocalDriveNumber;
pagingDevice->iRomPagingDriveNumber = romPagingDriveNumber;
pagingDevice->iDataPagingDriveNumber = dataPagingDriveNumber;
pagingDevice->iSwapSize = swapSize;
#ifdef __DEBUG_DEMAND_PAGING__
Kern::Printf("PagingDevice :");
Kern::Printf("iType 0x%x\n", pagingDevice->iType);
Kern::Printf("iReadUnitShift 0x%x\n", pagingDevice->iReadUnitShift);
Kern::Printf("iFirstLocalDriveNumber 0x%x\n", pagingDevice->iFirstLocalDriveNumber);
Kern::Printf("iRomPagingDriveNumber 0x%x\n", pagingDevice->iRomPagingDriveNumber);
Kern::Printf("iDataPagingDriveNumber 0x%x\n", pagingDevice->iDataPagingDriveNumber);
Kern::Printf("iSwapSize 0x%x\n", pagingDevice->iSwapSize);
#endif
// This table is indexed by DPagingDevice::TType
const char* DeviceName[] =
{
"Error",
"RomPagingDevice",
"CodePagingDevice",
"RomAndCodePagingDevice",
"DataPagingDevice",
"RomAndDataPagingDevice",
"CodeAndDataPagingDevice",
"RomAndCodeAndDataPagingDevice"
};
if(aPagingType & DPagingDevice::ECode)
{
for (i=0; i<aDriveCount; ++i)
pagingDevice->iDrivesSupported|=(0x1<<aPagingDriveList[i]);
}
pagingDevice->iName = DeviceName[aPagingType];
if (ThePinObjectAllocator == NULL)
ThePinObjectAllocator = new DPinObjectAllocator();
if(!ThePinObjectAllocator)
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not create ThePinObjectAllocator"));
OstTrace0(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT11, "RegisterPagingDevice: could not create ThePinObjectAllocator; KErrNoMemory");
return KErrNoMemory;
}
TInt r = ThePinObjectAllocator->Construct(KDynamicPagingLockCount, aNumPages);
if (r != KErrNone)
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not construct ThePinObjectAllocator"));
OstTrace1(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT12, "< RegisterPagingDevice: could not construct ThePinObjectAllocator; retval=%d",r);
return r;
}
// Register our DPagingDevice with the Kernel
r=Kern::InstallPagingDevice(pagingDevice);
#ifdef __DEBUG_DEMAND_PAGING__
Kern::Printf("Kern::InstallPagingDevice() r %d", r);
#endif
if (r!=KErrNone)
{
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not install paging device"));
OstTrace1(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT13, "< RegisterPagingDevice: could not install paging device; retval=%d", r);
delete pagingDevice;
return r;
}
// all hunky dory, save paging device and mark our media as pageable
ThePagingDevices[aPrimaryMedia->iMediaId] = pagingDevice; // association created between PrimaryMedia and PagingDevice via iMediaId
aPrimaryMedia->iPagingMedia = 1;
// mark our drives as pageable
p=aPagingDriveList;
if (aPagingType&DPagingDevice::ECode)
{
for (i=0; i<aDriveCount; ++i)
{
TLocDrv* pD=TheDrives[*p++];
pD->iPagingDrv=1;
}
}
// Flags to indicate that a paging device is registered and pinning of user requests may be required
aPrimaryMedia->iPagingMedia = 1;
// point the primary media to the paging device
aPrimaryMedia->iBody->iPagingDevice = pagingDevice;
if (aPagingType & DPagingDevice::ERom)
{
aPrimaryMedia->iRomPagingMedia = 1;
TheRomPagingMedia = aPrimaryMedia;
}
// Is data paging enabled in this ROM ?
TInt memModelAttributes = Kern::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
TBool dataPagingSupported = memModelAttributes & EMemModelAttrDataPaging;
#ifdef __DEBUG_DEMAND_PAGING__
Kern::Printf("memModelAttributes %08X", memModelAttributes);
Kern::Printf("DataPagingSupported %d", dataPagingSupported);
#endif
if (!dataPagingSupported)
{
#ifdef __DEBUG_DEMAND_PAGING__
if (aPagingType & DPagingDevice::EData)
{
Kern::Printf("Disabling data paging, not supported in this ROM");
}
#endif
aPagingType&= ~DPagingDevice::EData;
}
if (aPagingType & DPagingDevice::EData)
{
DataPagingDeviceRegistered = ETrue;
aPrimaryMedia->iDataPagingMedia = 1;
TheDataPagingMedia = aPrimaryMedia;
}
__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("< RegisterPagingDevice"));
OstTraceFunctionExit0( LOCDRV_REGISTERPAGINGDEVICE_EXIT14 );
return KErrNone;
}
#else //__DEMAND_PAGING__
#if !defined(__WINS__)
EXPORT_C TInt LocDrv::RegisterPagingDevice(DPrimaryMediaBase* , const TInt* , TInt , TUint , TInt , TUint )
{
return KErrNotSupported;
} // stub for def file
#endif // __WINS__
#endif //__DEMAND_PAGING__
/**
Registers a media device with physical memory addressing capabilities with the
Local Media Subsystem.
@param aPrimaryMedia A pointer to the primary DPrimaryMedia object associated
with the media device.
@param aMediaBlockSize The Minimum transfer size (bytes) for the media device.
@param aDmaMaxAddressable The Maximum Addressing Range for the media device's DMA controller, 0 if None.
@param aDmaAlignment The required memory alignment for the media device's DMA controller.
@return KErrNone, Always;
*/
EXPORT_C TInt LocDrv::RegisterDmaDevice(DPrimaryMediaBase* aPrimaryMedia,
TInt aMediaBlockSize, // Minimum transfer size (bytes) for the media
TInt aDmaMaxAddressable, // Max Addressing Range for DMA controller, 0 if None.
TInt aDmaAlignment) // DMA Alignment e.g. word alignment required = 2
{
OstTraceFunctionEntry0( LOCDRV_REGISTERDMADEVICE_ENTRY );
__KTRACE_OPT(KBOOT ,Kern::Printf("RegisterPhysicalAddrDevice: PM=0x%x BS=%d MaxAddr=%d DMA=%d",
aPrimaryMedia, aMediaBlockSize, aDmaMaxAddressable, aDmaAlignment));
OstTraceExt4( TRACE_INTERNALS, LOCDRV_REGISTERDMADEVICE, "aPrimaryMedia=0x%x; aMediaBlockSize=%d; aDmaMaxAddressable=%d; aDmaAlignment=%d", (TUint) aPrimaryMedia, (TInt) aMediaBlockSize, (TInt) aDmaMaxAddressable, (TInt) aDmaAlignment );
for (TInt i=0; i<KMaxLocalDrives; ++i)
{
TLocDrv* pL=TheDrives[i];
if (pL && pL->iPrimaryMedia == aPrimaryMedia && pL->iDmaHelper == NULL)
{
pL->iDmaHelper = new DDmaHelper;
__ASSERT_ALWAYS(pL != NULL, LOCM_FAULT());
// if no limit stated on addressing range use 1MB
TInt MaxAddress = aDmaMaxAddressable ? (1024*1024) : aDmaMaxAddressable;
TInt r = pL->iDmaHelper->Construct(MaxAddress, aMediaBlockSize, aDmaAlignment);
__ASSERT_ALWAYS(r == KErrNone, LOCM_FAULT());
}
}
OstTraceFunctionExit0( LOCDRV_REGISTERDMADEVICE_EXIT );
return KErrNone;
}
void GetDriveInfo(TDriveInfoV1& info)
{
OstTraceFunctionEntry1( GETDRIVEINFO_ENTRY, ( TUint )&( info ) );
TInt i;
TInt drives=0;
TUint32 sock_mask=0;
TInt sockets=0;
info.iRegisteredDriveBitmask = 0;
for (i=0; i<KMaxPBusSockets; ++i)
info.iSocketName[i].Zero();
for (i=0; i<KMaxLocalDrives; ++i)
{
TLocDrv* pL=TheDrives[i];
if (pL)
{
++drives;
TInt sockNum;
DPrimaryMediaBase* pM=pL->iPrimaryMedia;
if (pM->IsRemovableDevice(sockNum))
{
if (!(sock_mask & (1<<sockNum)))
{
info.iSocketName[sockNum]=*DriveNames[i];
__KTRACE_OPT(KLOCDRV,Kern::Printf("Socket %d device %d name %lS", sockNum, pM->iDevice, DriveNames[i]));
OstTraceExt2( TRACE_INTERNALS, GETDRIVEINFO1, "Socket=%d; device=%d", sockNum, (TUint) pM->iDevice );
if ( (sockNum + 1) > sockets )
sockets = sockNum + 1;
}
sock_mask |= (1<<sockNum);
}
info.iDriveName[i]=*DriveNames[i];
__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d device %d name %lS",i,pM->iDevice,DriveNames[i]));
OstTraceExt2( TRACE_INTERNALS, GETDRIVEINFO2, "Drive=%d; device=%d", i, (TUint) pM->iDevice );
info.iRegisteredDriveBitmask |= (0x01 << i);
}
}
info.iTotalSupportedDrives=drives;
info.iTotalSockets=sockets;
info.iRuggedFileSystem=ETrue;
__KTRACE_OPT(KLOCDRV,Kern::Printf("Total drives=%d, sockets=%d",drives,sockets));
OstTraceExt2( TRACE_INTERNALS, GETDRIVEINFO3, "Total drives=%d; sockets=%d", drives, sockets );
OstTraceFunctionExit0( GETDRIVEINFO_EXIT );
}
#if defined(__DEMAND_PAGING__) && defined(__CONCURRENT_PAGING_INSTRUMENTATION__)
void ResetConcurrencyStats(DMediaPagingDevice* aDevice, TMediaPagingStats aStats)
{
NKern::FMWait(&aDevice->iInstrumentationLock);
switch(aStats)
{
case EMediaPagingStatsRom:
aDevice->iServicingROM=0;
memclr(&aDevice->iROMStats,sizeof(SMediaROMPagingConcurrencyInfo));
break;
case EMediaPagingStatsCode:
aDevice->iServicingCode=0;
memclr(&aDevice->iCodeStats,sizeof(SMediaCodePagingConcurrencyInfo));
break;
case EMediaPagingStatsDataIn:
aDevice->iServicingDataIn=0;
memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
break;
case EMediaPagingStatsDataOut:
aDevice->iServicingDataOut=0;
memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
break;
case EMediaPagingStatsAll:
aDevice->iServicingROM=0;
aDevice->iServicingCode=0;
aDevice->iServicingDataIn=0;
aDevice->iServicingDataOut=0;
memclr(&aDevice->iROMStats,sizeof(SMediaROMPagingConcurrencyInfo));
memclr(&aDevice->iCodeStats,sizeof(SMediaCodePagingConcurrencyInfo));
memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
break;
}
NKern::FMSignal(&aDevice->iInstrumentationLock);
}
#endif
#if defined(__DEMAND_PAGING__) && defined(__DEMAND_PAGING_BENCHMARKS__)
void ResetBenchmarkStats(DMediaPagingDevice* aDevice, TMediaPagingStats aStats)
{
NKern::FMWait(&aDevice->iInstrumentationLock);
switch(aStats)
{
case EMediaPagingStatsRom:
aDevice->iROMBenchmarkData.iCount = 0;
aDevice->iROMBenchmarkData.iTotalTime = 0;
aDevice->iROMBenchmarkData.iMaxTime = 0;
aDevice->iROMBenchmarkData.iMinTime = KMaxTInt;
break;
case EMediaPagingStatsCode:
aDevice->iCodeBenchmarkData.iCount = 0;
aDevice->iCodeBenchmarkData.iTotalTime = 0;
aDevice->iCodeBenchmarkData.iMaxTime = 0;
aDevice->iCodeBenchmarkData.iMinTime = KMaxTInt;
break;
case EMediaPagingStatsDataIn:
aDevice->iDataInBenchmarkData.iCount = 0;
aDevice->iDataInBenchmarkData.iTotalTime = 0;
aDevice->iDataInBenchmarkData.iMaxTime = 0;
aDevice->iDataInBenchmarkData.iMinTime = KMaxTInt;
break;
case EMediaPagingStatsDataOut:
aDevice->iDataOutBenchmarkData.iCount = 0;
aDevice->iDataOutBenchmarkData.iTotalTime = 0;
aDevice->iDataOutBenchmarkData.iMaxTime = 0;
aDevice->iDataOutBenchmarkData.iMinTime = KMaxTInt;
break;
case EMediaPagingStatsAll:
aDevice->iDataInBenchmarkData.iCount = 0;
aDevice->iDataInBenchmarkData.iTotalTime = 0;
aDevice->iDataInBenchmarkData.iMaxTime = 0;
aDevice->iDataInBenchmarkData.iMinTime = KMaxTInt;
aDevice->iDataOutBenchmarkData.iCount = 0;
aDevice->iDataOutBenchmarkData.iTotalTime = 0;
aDevice->iDataOutBenchmarkData.iMaxTime = 0;
aDevice->iDataOutBenchmarkData.iMinTime = KMaxTInt;
aDevice->iROMBenchmarkData.iCount = 0;
aDevice->iROMBenchmarkData.iTotalTime = 0;
aDevice->iROMBenchmarkData.iMaxTime = 0;
aDevice->iROMBenchmarkData.iMinTime = KMaxTInt;
aDevice->iCodeBenchmarkData.iCount = 0;
aDevice->iCodeBenchmarkData.iTotalTime = 0;
aDevice->iCodeBenchmarkData.iMaxTime = 0;
aDevice->iCodeBenchmarkData.iMinTime = KMaxTInt;
break;
}
NKern::FMSignal(&aDevice->iInstrumentationLock);
}
#endif
TInt MediaHalFunction(TAny*, TInt aFunction, TAny* a1, TAny* a2)
{
TInt r=KErrNotSupported;
switch (aFunction)
{
case EMediaHalDriveInfo:
{
(void) a2;
TDriveInfoV1Buf infoBuf;
TDriveInfoV1& info=infoBuf();
GetDriveInfo(info);
Kern::InfoCopy(*(TDes8*)a1,infoBuf);
r=KErrNone;
break;
}
#if defined(__DEMAND_PAGING__) && defined(__CONCURRENT_PAGING_INSTRUMENTATION__)
case EMediaHalGetROMConcurrencyInfo:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device = drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
NKern::FMWait(&device->iInstrumentationLock);
SMediaROMPagingConcurrencyInfo info=device->iROMStats;
NKern::FMSignal(&device->iInstrumentationLock);
kumemput32(a2,&info,sizeof(info));
r=KErrNone;
break;
}
case EMediaHalGetCodeConcurrencyInfo:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
NKern::FMWait(&device->iInstrumentationLock);
SMediaCodePagingConcurrencyInfo info=device->iCodeStats;
NKern::FMSignal(&device->iInstrumentationLock);
kumemput32(a2,&info,sizeof(info));
r=KErrNone;
break;
}
case EMediaHalGetDataConcurrencyInfo:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device = drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
NKern::FMWait(&device->iInstrumentationLock);
SMediaDataPagingConcurrencyInfo info=device->iDataStats;
NKern::FMSignal(&device->iInstrumentationLock);
kumemput32(a2,&info,sizeof(info));
r=KErrNone;
break;
}
case EMediaHalResetConcurrencyInfo:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
TUint index=(TInt)a2;
if(index>EMediaPagingStatsCode)
break;
ResetConcurrencyStats(device, (TMediaPagingStats)index);
r=KErrNone;
break;
}
#endif
#if defined(__DEMAND_PAGING__) && defined(__DEMAND_PAGING_BENCHMARKS__)
case EMediaHalGetROMPagingBenchmark:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
NKern::FMWait(&device->iInstrumentationLock);
SPagingBenchmarkInfo info = device->iROMBenchmarkData;
NKern::FMSignal(&device->iInstrumentationLock);
kumemput32(a2,&info,sizeof(info));
r=KErrNone;
break;
}
case EMediaHalGetCodePagingBenchmark:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
NKern::FMWait(&device->iInstrumentationLock);
SPagingBenchmarkInfo info = device->iCodeBenchmarkData;
NKern::FMSignal(&device->iInstrumentationLock);
kumemput32(a2,&info,sizeof(info));
r=KErrNone;
break;
}
case EMediaHalGetDataInPagingBenchmark:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
NKern::FMWait(&device->iInstrumentationLock);
SPagingBenchmarkInfo info = device->iDataInBenchmarkData;
NKern::FMSignal(&device->iInstrumentationLock);
kumemput32(a2,&info,sizeof(info));
r=KErrNone;
break;
}
case EMediaHalGetDataOutPagingBenchmark:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
NKern::FMWait(&device->iInstrumentationLock);
SPagingBenchmarkInfo info = device->iDataOutBenchmarkData;
NKern::FMSignal(&device->iInstrumentationLock);
kumemput32(a2,&info,sizeof(info));
r=KErrNone;
break;
}
case EMediaHalResetPagingBenchmark:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
TUint index=(TInt)a2;
if(index>EMediaPagingStatsCode)
break;
ResetBenchmarkStats(device, (TMediaPagingStats)index);
r=KErrNone;
break;
}
case EMediaHalGetPagingInfo:
{
TInt drvNo=(TInt)a1;
TLocDrv* drv=TheDrives[drvNo];
if(!drv)
break;
DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
if(!device)
break;
NKern::FMWait(&device->iInstrumentationLock);
SMediaPagingInfo info = device->iMediaPagingInfo;
NKern::FMSignal(&device->iInstrumentationLock);
kumemput32(a2,&info,sizeof(info));
r=KErrNone;
break;
}
#endif
default:
break;
}
return r;
}
/******************************************************************************
Partition table scanner
******************************************************************************/
#ifdef _DEBUG
#define DMEMDUMP(base,size) DbgMemDump((TLinAddr)base,size)
void DbgMemDump(TLinAddr aBase, TInt aSize)
{
TInt off;
const TUint8* p=(const TUint8*)aBase;
NKern::Lock();
for (off=0; off<aSize; off+=16, p+=16)
{
Kern::Printf("%04x: %02x %02x %02x %02x %02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x",
off, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
}
NKern::Unlock();
}
#else
#define DMEMDUMP(base,size)
#endif
EXPORT_C void TPartitionTableScanner::Set(TUint8* aSectorBuffer, TPartitionEntry* aEntry, TInt aMaxPartitions, TInt64 aMediaSize)
{
__KTRACE_OPT(KLOCDRV, Kern::Printf("TPartitionTableScanner @ %08x : buf %08x entry %08x max %d sz %08x %08x",
this, aSectorBuffer, aEntry, aMaxPartitions, I64HIGH(aMediaSize), I64LOW(aMediaSize)));
OstTraceExt4( TRACE_INTERNALS, TPARTITIONTABLESCANNER_SET, "TPartitionTableScanner at 0x%08x; aSectorBuffer=0x%08x; aEntry=0x%08x; aMaxPartitions=%d", (TUint) this, (TUint) aSectorBuffer, (TUint) aEntry, aMaxPartitions );
__ASSERT_ALWAYS(aMaxPartitions>0, LOCM_FAULT());
memclr(this, sizeof(TPartitionTableScanner));
iLBA = -1;
iSectorBuffer = aSectorBuffer;
iFirstEntry = aEntry;
iNextEntry = aEntry;
iLimit = aEntry + aMaxPartitions;
iMediaSize = aMediaSize;
}
EXPORT_C TInt TPartitionTableScanner::NumberOfPartitionsFound() const
{
TInt n = iNextEntry - iFirstEntry;
__KTRACE_OPT(KLOCDRV, Kern::Printf("TPartitionTableScanner N=%d", n));
OstTrace1( TRACE_INTERNALS, TPARTITIONTABLESCANNER_NUMBERPARTITIONS, "Number of partitions=%d", n );
return n;
}
TPartitionTableScanner::SPart::SPart(const TUint8* a)
{
iBootInd = a[0];
iType = a[4];
iRSS = a[8]|(a[9]<<8)|(a[10]<<16)|(a[11]<<24);
iSectors = a[12]|(a[13]<<8)|(a[14]<<16)|(a[15]<<24);
__KTRACE_OPT(KLOCDRV, Kern::Printf("SPart: BI=%02x TYPE=%02x RSS=%08x SIZE=%08x", iBootInd, iType, iRSS, iSectors));
OstTraceExt4(TRACE_INTERNALS, TPARTITIONTABLESCANNER_SPART_SPART, "SPart: iBootInd=%02x; iType=%02x; iRSS=%08x; iSectors=%08x", (TUint) iBootInd, (TUint) iType, (TUint) iRSS, (TUint) iSectors);
}
TInt TPartitionTableScanner::MakeEntry(const SPart& a)
{
OstTraceFunctionEntry1( TPARTITIONTABLESCANNER_MAKEENTRY_ENTRY, this );
if (iNextEntry == iLimit)
{
OstTraceFunctionExitExt( TPARTITIONTABLESCANNER_MAKEENTRY_EXIT1, this, KErrOverflow );
return KErrOverflow;
}
if (a.iRSS<=0 || a.iSectors<=0 || a.iRSS>=iMediaSize)
{
OstTraceFunctionExitExt( TPARTITIONTABLESCANNER_MAKEENTRY_EXIT2, this, KErrCorrupt );
return KErrCorrupt;
}
if (TUint64(a.iRSS) + TUint64(a.iSectors) > TUint64(iMediaSize))
{
OstTraceFunctionExitExt( TPARTITIONTABLESCANNER_MAKEENTRY_EXIT3, this, KErrCorrupt );
return KErrCorrupt;
}
iNextEntry->iBootIndicator = a.iBootInd;
iNextEntry->iPartitionType = a.iType;
iNextEntry->iPartitionBaseAddr = TInt64(a.iRSS)<<ESectorShift;
iNextEntry->iPartitionLen = TInt64(a.iSectors)<<ESectorShift;
++iNextEntry;
OstTraceFunctionExitExt( TPARTITIONTABLESCANNER_MAKEENTRY_EXIT4, this, KErrNone );
return KErrNone;
}
EXPORT_C TInt64 TPartitionTableScanner::NextLBA()
{
OstTraceFunctionEntry0( TPARTITIONTABLESCANNER_NEXTLBA_ENTRY );
__KTRACE_OPT(KLOCDRV, Kern::Printf(">TPartitionTableScanner iLBA=%08x %08x", I64HIGH(iLBA), I64LOW(iLBA)));
OstTraceExt2( TRACE_INTERNALS, TPARTITIONTABLESCANNER_NEXTLBA1, "TPartitionTableScanner iLBA=%08x %08x", I64HIGH(iLBA), I64LOW(iLBA) );
TInt r;
TUint8* b = iSectorBuffer;
TUint8* pS = b + 0x1be;
TUint8* pE = pS + 64;
TUint8* p = pS;
TInt orig_sp = iStackPointer;
TInt sp;
if (iLBA < 0)
{
iLBA = 0;
goto end;
}
__KTRACE_OPT(KLOCDRV,DMEMDUMP(b, ESectorSize));
if (b[ESectorSize-2]!=0x55 || b[ESectorSize-1]!=0xaa)
{
__KTRACE_OPT(KLOCDRV, Kern::Printf("Bad signature"));
OstTrace0( TRACE_INTERNALS, TPARTITIONTABLESCANNER_NEXTLBA2, "Bad signature" );
iLBA = KErrCorrupt;
goto end;
}
if (iLBA==0 && iNextEntry==iFirstEntry)
{
// Look for bootable partition first
for (; p<pE; p+=16)
{
SPart pt(p);
if (pt.iBootInd==0x80 && pt.iType && pt.iSectors>0)
{
p[4] = 0;
r = MakeEntry(pt);
if (r!=KErrNone)
{
iLBA = r;
goto end;
}
}
}
}
// Look for extended partitions
for (p=pE-16; p>=pS; p-=16)
{
SPart pt(p);
if ((pt.iType==0x05 || pt.iType==0x0f) && pt.iSectors>0)
{
// This one is an EBR
p[4] = 0;
if (iStackPointer == EMaxNest)
{
if (iStackPointer == orig_sp)
continue;
--iStackPointer;
for(sp = orig_sp; sp<iStackPointer; ++sp)
iStack[sp] = iStack[sp+1];
}
iStack[iStackPointer].iRSS = pt.iRSS;
iStack[iStackPointer].iSectors = pt.iSectors;
++iStackPointer;
#ifdef _DEBUG
for (sp=0; sp<iStackPointer; ++sp)
{
const TInt64& rss = iStack[sp].iRSS;
const TInt64& size = iStack[sp].iSectors;
__KTRACE_OPT(KLOCDRV, Kern::Printf("Stack[%d] RSS %08x %08x SIZE %08x %08x", sp,
I64HIGH(rss), I64LOW(rss), I64HIGH(size), I64LOW(size) ));
OstTraceExt5(TRACE_INTERNALS, PARTITIONTABLESCANNER_NEXTLBA3, "Stack[%d] RSS 0x%x 0x%x SIZE 0x%08x 0x%08x", (TInt) sp, (TUint) I64HIGH(rss), (TUint) I64LOW(rss), (TUint) I64HIGH(size), (TUint) I64LOW(size));
}
#endif
}
}
// Look for other data partitions
for (p=pS; p<pE; p+=16)
{
SPart pt(p);
if (pt.iType && pt.iSectors>0)
{
pt.iRSS += TUint32(iLBA); // data partitions are specified relative to the EBR they appear in
r = MakeEntry(pt);
if (r!=KErrNone)
{
iLBA = r;
goto end;
}
}
}
// If any EBRs on stack, pop off the first and process it
if (iStackPointer)
{
--iStackPointer;
iLBA = iFirstEBR + iStack[iStackPointer].iRSS; // LBA of second and subsequent EBR is specified relative to first EBR
if (!iFirstEBR)
iFirstEBR = iLBA;
}
else
iLBA = KErrEof; // finished
end:
__KTRACE_OPT(KLOCDRV, Kern::Printf("<TPartitionTableScanner iLBA=%08x %08x", I64HIGH(iLBA), I64LOW(iLBA)));
OstTraceExt2( TRACE_INTERNALS, TPARTITIONTABLESCANNER_NEXTLBA3, "TPartitionTableScanner iLBA=0x%08x 0x%08x", I64HIGH(iLBA), I64LOW(iLBA) );
OstTraceFunctionExit0( TPARTITIONTABLESCANNER_NEXTLBA_EXIT );
return iLBA;
}
/**
* Returns Address and Length of next contiguous Physical memory fragment
*
* @param aAddr On success, populated with the Physical Address of the next fragment.
* @param aLen On success, populated with the length in bytes of the next fragment.
*
* @return KErrNone, if successful;
* KErrNoMemory, if no more memory fragments left.
* KErrNotSupported, if Physical Memory addressing is not supported by this Media.
*/
EXPORT_C TInt TLocDrvRequest::GetNextPhysicalAddress(TPhysAddr& aAddr, TInt& aLen)
{
OstTraceExt2(TRACE_FLOW, TLOCDRVREQUEST_GETNEXTPHYSICALADDRESS_ENTRY, "> TLocDrvRequest::GetNextPhysicalAddress;aAddr=%x;aLen=%d;", (TUint) &aAddr, aLen );
if (Flags() & EPhysAddr)
{
#ifdef __DEMAND_PAGING__
if (DMediaPagingDevice::PagingRequest(*this))
{
return DDmaHelper::GetPhysicalAddress(*this, aAddr, aLen);
}
#endif
return Drive()->iDmaHelper->GetPhysicalAddress(aAddr, aLen);
}
else
{
OstTraceFunctionExitExt( TLOCDRVREQUEST_GETNEXTPHYSICALADDRESS_EXIT, this, KErrNotSupported );
return KErrNotSupported;
}
}
/******************************************************************************
Entry point
******************************************************************************/
DECLARE_STANDARD_EXTENSION()
{
__KTRACE_OPT(KBOOT,Kern::Printf("Starting LOCMEDIA extension"));
// install the HAL function
TInt r=Kern::AddHalEntry(EHalGroupMedia,MediaHalFunction,NULL);
#ifdef __DEMAND_PAGING__
if (r==KErrNone)
{
__KTRACE_OPT(KBOOT,Kern::Printf("Creating LocDrv device"));
DLocalDriveFactory* device = new DLocalDriveFactory;
if (device==NULL)
r=KErrNoMemory;
else
r=Kern::InstallLogicalDevice(device);
__KTRACE_OPT(KBOOT,Kern::Printf("Installing LocDrv device in kernel returned %d",r));
}
#endif // __DEMAND_PAGING__
return r;
}