// 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\include\drivers\locmedia.h
// 
//

#ifndef LOCMEDIA_H
#define LOCMEDIA_H
#include <plat_priv.h>
#include <d32locd.h>

#if defined(_DEBUG) && defined(__DEMAND_PAGING__)
#define __CONCURRENT_PAGING_INSTRUMENTATION__
#endif
#if defined(_DEBUG) && defined(__DEMAND_PAGING__)
#define __DEMAND_PAGING_BENCHMARKS__
#endif

#ifdef __WINS__
	#define __EMULATOR_DMA_SUMULATION__
#endif

/**
@publishedPartner
@released

A media driver priority value.

The value can be returned by a media driver's PDD factory Info() function,
and allows Symbian OS to decide the order in which media drivers are to be opened.

The value is relative to the other media driver priority values.

@see DPhysicalDevice::Info()
*/
const TInt KMediaDriverPriorityHigh=2;




/**
@publishedPartner
@released

A media driver priority value.

The value can be returned by a media driver's PDD factory Info() function,
and allows Symbian OS to decide the order in which media drivers are to be opened.

The value is relative to the other media driver priority values, and is
the one most commonly used.

@see DPhysicalDevice::Info()
*/
const TInt KMediaDriverPriorityNormal=1;




/**
@publishedPartner
@released

A media driver priority value.

The value can be returned by a media driver's PDD factory Info() function,
and allows Symbian OS to decide the order in which media drivers are to be opened.

The value is relative to the other media driver priority values.

@see DPhysicalDevice::Info()
*/
const TInt KMediaDriverPriorityLow=0;




/**
@publishedPartner
@released

Media driver interface major version number.
*/
const TInt KMediaDriverInterfaceMajorVersion=1;




/**
@publishedPartner
@released

Media driver interface minor version number.
*/
const TInt KMediaDriverInterfaceMinorVersion=0;





/**
@publishedPartner
@released

Media driver interface build number.
*/
const TInt KMediaDriverInterfaceBuildVersion=160;




/**
@publishedPartner
@released
*/
const TInt KMediaDriverDeferRequest=1;




/**
@internalTechnology
*/
#define __TRACE_TIMING(x)
//#define __TRACE_TIMING(x) *(TInt*)0x63000ff0=x

/**
@internalComponent
*/
NONSHARABLE_CLASS(DLocalDriveFactory) : public DLogicalDevice
	{
public:
	DLocalDriveFactory();
	virtual TInt Install();
	virtual void GetCaps(TDes8 &aDes) const;
	virtual TInt Create(DLogicalChannelBase*& aChannel);
	};

class TLocDrv;
class DLocalDrive;

/**
@internalComponent
*/
NONSHARABLE_CLASS(TLocalDriveCleanup) : public TThreadCleanup
	{
public:
	TLocalDriveCleanup();
	virtual void Cleanup();
	inline DLocalDrive& LocalDrive();
	};



class TLocDrvRequest;
class DPrimaryMediaBase;

/**
@publishedPartner
@released

This class is strictly internal to Symbian; the only part of this class that
is publicly exposed to partners is the TRequestId enum.

@see DLocalDrive::TRequestId
*/
NONSHARABLE_CLASS(DLocalDrive) : public DLogicalChannelBase
	{
public:
	/**
	Identifies the specific local drive operation.
	*/
	enum TRequestId
		{
		/**
		Requests information about the size, type, and attributes of the media.
		*/
		ECaps=0,
		
		/**
		Requests an asynchronous read from the media device.
		*/
		ERead=1,
		
		/**
		Requests an asynchronous write to the media device.
		*/
		EWrite=2,
		
		/**
		Requests the formatting of a section of the media
		*/
		EFormat=3,
		
		/**
		A request to expand the total size of the media.
		*/
		EEnlarge=4,
		
		/**
		A request to reduce the total size of the media.
		*/
		EReduce=5,
		
		/**
		A request to force a remount of the media.
		*/
		EForceMediaChange=6,
		
		/**
		Requests an attempt to lock the media with a password.
		*/
		EPasswordLock=7,
		
		/**
		Requests an attempt to unlock the media.
		*/
		EPasswordUnlock=8,
		
		/**
		Requests an attempt to remove the password from the media.
		*/
		EPasswordClear=9,
		
		/**
		Requests an read of the password store.
		*/
		EReadPasswordStore=10,
		
		/**
		Requests a write of the password store.
		*/
		EWritePasswordStore=11,
		
		/** 
		A request to get the length of the password store.
		*/
		EPasswordStoreLengthInBytes=12,
		/** 
		A Control IO request
		*/
		EControlIO=13,
		/** 
		A request to force an erase of the password from the media
		*/
		EPasswordErase=14,

		/** 
		A delete notification from the file system
		*/
		EDeleteNotify=15,

		/** 
		A request for information on the last error
		*/
		EGetLastErrorInfo=16,

		EFirstReqNumberReservedForPaging=17,
		// DO NOT REUSE ANY OF THE REQUEST NUMBERS BETWEEN THIS AND THE LAST RESERVED REQ NUMBER
		// ALSO DO NOT INSERT ANY REQUEST NUMBERS BEFORE THIS, AS THIS WILL BE A COMPATIBILITY BREEAK
		ELastReqNumberReservedForPaging=31,

		/**
		Query device 
		*/
		EQueryDevice=32,

		};
public:
	DLocalDrive(); 
	~DLocalDrive();
public:
	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); /**< @internalComponent */
	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);                      /**< @internalComponent */
public:
	void NotifyChange(DPrimaryMediaBase& aPrimaryMedia, TBool aMediaChange);
public:
	inline void Deque();                 /**< @internalComponent */

private:
#ifdef __DEMAND_PAGING__
	TInt LockMountInfo(DPrimaryMediaBase& aPrimaryMedia, TLocDrvRequest& aReq);
	void UnlockMountInfo(DPrimaryMediaBase& aPrimaryMedia);
#endif
	TInt ReadPasswordData(TLocDrvRequest& aReq, TLocalDrivePasswordData& aPswData, TMediaPassword& aOldPasswd, TMediaPassword& aNewPasswd);

public:
	TLocDrv* iDrive;							/**< @internalComponent */
	SDblQueLink iLink;							/**< @internalComponent */
	TClientDataRequest<TBool>* iNotifyChangeRequest;	/**< @internalComponent */
	TLocalDriveCleanup iCleanup;				 /**< @internalComponent */
	};

/**
@internalComponent
*/
inline DLocalDrive& TLocalDriveCleanup::LocalDrive()
	{ return *_LOFF(this,DLocalDrive,iCleanup); }




/**
@publishedPartner
@released

A class that encapsulates the request information received from the client,
and gives the media driver access to the request ID and other associated
parameters, such as the request length, offset, the requesting thread,
source and destination address etc.

An object of this type is passed to DMediaDriver::Request().

@see DMediaDriver::Request()
*/
class TLocDrvRequest : public TThreadMessage
	{
public:

    /** 
	@internalComponent
    */
	enum TFlags
		{
		EWholeMedia=1,
		EAdjusted=2,
		EPhysAddr=0x04,
		EPaging=0x08,				// a paging request
		EBackgroundPaging=0x10,		// a background paging request. @see DMediaPagingDevice::Write()
		ECodePaging=0x20,			// a code paging request
		EDataPaging=0x40,			// a data paging request
		ETClientBuffer=0x80,		// RemoteDes() points to a TClientBuffer
		EKernelBuffer=0x100,		// RemoteDes() points to a kernel-side buffer
		};
public:
    
    /**
    Gets a reference to the object containing the request information.
    
    @return The request information.
    */
	inline static TLocDrvRequest& Get()
		{return (TLocDrvRequest&)Kern::Message();}
	
		
    /**
    Gets the request ID.
    
    For media drivers, this is one of the DLocalDrive::TRequestId enumerated values.
    
    @return The request ID.
    
    @see DLocalDrive::TRequestId
    */
	inline TInt& Id()
		{return *(TInt*)&iValue;}
		
		
    /**
    Gets the position on the media on which the request operates. 
    
    This applies to operations ERead, EWrite and EFormat.

    Note that the partition offset is taken into account by the underlying
    local media subsystem.
    
    @return The position on the media.
    
    @see TRequestId::ERead
    @see TRequestId::EWrite
    @see TRequestId::EFormat
    */		
	inline Int64& Pos()
		{return *(Int64*)&iArg[0];}
	
	
	/**
	Gets the length associated with the operation.
	
	This is the number of bytes associated with the media request.
	It applies to operations ERead, EWrite and EFormat.
	
	@return The length, in bytes.
	
    @see TRequestId::ERead
    @see TRequestId::EWrite
    @see TRequestId::EFormat
	*/
	inline Int64& Length()
		{return *(Int64*)&iArg[2];}
		
	
	/**
	Gets a pointer to the remote thread that requested the operation.
	
	This may be used to access the data to be read from the remote thread's process,
	or the area to which data is to be written in the remote thread's process.
	However, it is recommended that	such operations be performed
	using ReadRemote() and WriteRemote()
	
	@return A reference to a pointer to the remote thread.
	
	@see TLocDrvRequest::ReadRemote()
	@see TLocDrvRequest::WriteRemote()
	*/
	inline DThread*& RemoteThread()
		{return *(DThread**)&iArg[4];}
		
		
	/**
	Gets a pointer to the descriptor in the remote thread's process that
	contains the data to be read, or is the target for data to be written.
	
    However, it is recommended that such read or write operations be performed
    using ReadRemote() and WriteRemote().
    
    @return A reference to a pointer to the remote descriptor.

    @see TLocDrvRequest::ReadRemote()
	@see TLocDrvRequest::WriteRemote()
	*/	
	inline TAny*& RemoteDes()
		{return *(TAny**)&iArg[5];}
		
		
    /**
    Gets the offset within the descriptor in the remote thread's process.
    
    @return The offset within the descriptor.
    */
	inline TInt& RemoteDesOffset()
		{return *(TInt*)&iArg[6];}
		
		
	/**
	@internalComponent
	*/
	inline TInt& Flags()
		{return *(TInt*)&iArg[7];}
		
		
	/**
	@internalComponent
	*/
	inline TLocDrv*& Drive()
		{return *(TLocDrv**)&iArg[8];}
		
		
	/**
	@internalComponent
	*/
	inline TInt& DriverFlags()
		{return *(TInt*)&iArg[9];}


	/**
	Returns true if Physical memory addresses are available for this TLocDrvRequest.
	@return ETrue if a physical memory address is available.
	*/
	inline TBool IsPhysicalAddress()
		{return Flags() & EPhysAddr;}
public:
	TInt ProcessMessageData(TAny* args);
	void CloseRemoteThread();
	IMPORT_C TInt ReadRemote(TDes8* aDes, TInt anOffset);
	IMPORT_C TInt ReadRemote(const TAny* aSrc, TDes8* aDes);
	IMPORT_C TInt ReadRemoteRaw(TAny* aDes, TInt aSize);
	IMPORT_C TInt WriteRemote(const TDesC8* aDes, TInt anOffset);
	IMPORT_C TInt WriteRemoteRaw(const TAny* aSrc, TInt aSize);
	IMPORT_C TInt CheckAndAdjustForPartition();
#if !defined(__WINS__)
	IMPORT_C TInt WriteToPageHandler(const TAny* aSrc, TInt aSize, TInt anOffset);
	IMPORT_C TInt ReadFromPageHandler(TAny* aDst, TInt aSize, TInt anOffset);
#endif // __WINS__
	IMPORT_C TInt GetNextPhysicalAddress(TPhysAddr& aPhysAddr, TInt& aLength);
	};




/**
@internalComponent
*/
inline void DLocalDrive::Deque()
	{ iLink.Deque(); }




/**
@publishedPartner
@released

Defines a structure used to contain information that describes an individual
partition. 

There is one of these for each partition that exists on a media device.

@see TPartitionInfo
*/
class TPartitionEntry
	{
public:
     
    /**
    The start address of the partition, described as a relative offset,
    in bytes, from the start of the media.
    
    This value is used by the local media subsystem to calculate
    the absolute address on the media whenever an access such as a Read,
    Write or Format request is made.
    */
	Int64 iPartitionBaseAddr;
 
 	
	/**
	The length of the partition, in bytes.
	*/
	Int64 iPartitionLen;

	
	/**
	The Boot Indicator record, as described in the Master Boot Record on
	FAT Partitioned devices.

	This is currently unused by the local media subsystem.
	*/
	TUint16 iBootIndicator;
	
	
	/**
	Describes the type of partition.
	
	The File Server uses this to decide the type of filesystem to be mounted
	on the partition. 
	
	Symbian OS supports many partition types, as defined in partitions.h.
	You are, however, free to invent your own partition type, on which
	you could, for example, mount your own filesystem. However, make sure 
	that your partition type does not clash with an existing partition type.
	
	Note that a media driver does not does not have to verify that
	the partition actually contains a file system of this type; it just sets
	this value to indicate the intended use for this partition.
	*/
	TUint16 iPartitionType;
	};




/**
@publishedPartner
@released

A constant that defines the maximum number of partitions that can exist on
a media device.

@see TPartitionInfo::iPartitionCount
*/
const TInt KMaxPartitionEntries=0x10;




/**
@publishedPartner
@released

Contains partition information for a media device.

An object of this type is passed to the media driver's implementation of
DMediaDriver::PartitionInfo() to be filled in.

@see DMediaDriver::PartitionInfo()
*/
class TPartitionInfo
	{
public:

    /**
    Default constructor that clears this object's memory to binary zeroes.
    */
	TPartitionInfo();
public:

    /**
    The total size of the media, in bytes.
    */
	Int64 iMediaSizeInBytes;
	
	
	/**
	The total number of partitions that exist on the media.
	
	This is always less than or equal to KMaxPartitionEntries.
	
    @see KMaxPartitionEntries
	*/
	TInt iPartitionCount;
	
	
	/**
	Information that describes each individual partition on the device.
	
	Each partition is represented by an array of TPartitionEntry objects. 
	Each entry must be created in the order of the start offset, so that 
	iEntry[0] specifies the partition with
	the smallest iPartitionBaseAddr value.
	
	@see TPartitionEntry::iPartitionBaseAddr
	@see TPartitionEntry
	*/
	TPartitionEntry iEntry[KMaxPartitionEntries];
	};




class DMedia;
class DPrimaryMediaBase;
class DMediaDriver;
#ifdef __DEMAND_PAGING__
class DFragmentationPagingLock;
#endif
class DDmaHelper;

/**
@internalComponent
*/
class TLocDrv : public TPartitionEntry
	{
public:
	TLocDrv(TInt aDriveNumber);
public:
	inline TInt Connect(DLocalDrive* aLocalDrive);
	inline void Disconnect(DLocalDrive* aLocalDrive);
	inline TInt Request(TLocDrvRequest& aRequest);
public:
	TInt iDriveNumber;
	DMedia* iMedia;
	DPrimaryMediaBase* iPrimaryMedia;
	TInt iPartitionNumber;
	TErrorInfo iLastErrorInfo;
#ifdef __DEMAND_PAGING__
	TInt iSpare0;
	TUint8 iPagingDrv;
	TUint8 iSpare1;
	TUint8 iSpare2;
	TUint8 iSpare3;
#endif
	DDmaHelper* iDmaHelper;
	};

/**
@publishedPartner
@released

Kernel-side representation of a media entity. A DMedia object instantiates a 
media driver to provide access to the physical media.

Multiple DMedia objects may be required by some devices, e.g. multi-media cards
with combined SRAM and Flash or cards containing user and protected areas.
*/
class DMedia : public DBase
	{
public:
	/**
	Declaration of all legal states for the media driver.
	*/
	enum TMediaState
		{
		/** 
		Media is powered down and the media drivers are closed. This is the 
		initial state when a media driver is created and the final state when
		the driver is closed.
		*/
		EClosed=0,

		/** Media driver has started powerup sequence. */
		EPoweringUp1=1,

		/** Media is being opened. */
		EOpening=2,

		/** Media is open and the partition information is being read. */
		EReadPartitionInfo=3,
		
		/** The media driver is open and ready to accept commands. */
		EReady=4,

		/** Not used. */
		EAborted=5,

		/** Powering up with media drivers open. */
		EPoweringUp2=6,

		/** Not used. */
		ERecovering=7,

		/** The media is powered down, but the media driver still exists. */
		EPoweredDown=8 // powered down with media drivers open
		};

public:
	IMPORT_C virtual TInt Create(TMediaDevice aDevice, TInt aMediaId, TInt);
	void Close();
public:
	inline Int64 MediaLenInBytes();
	inline TMediaDevice DeviceType();
	inline TInt PartitionCount();
	inline Int64 PartitionBaseAddr(TInt aPartition);
	inline Int64 PartitionLen(TInt aPartition);
public:
    /** Not used. */
	static TInt MediaCallBack(TAny *aPtr);
public:
	/**
	The unique ID associated with this media entity. 
	ID allocated when the media is first created.
	
	@see LocDrv::RegisterMediaDevice
	*/
	TInt iMediaId;

	/**
	The unique ID for the device.

	@see TMediaDevice
	*/
	TMediaDevice iDevice;

	/**
	Partition information for the media device.

	@see TPartitionInfo
	*/
	TPartitionInfo iPartitionInfo;

	/**
	The media's physical device driver.

	@see DMediaDriver
	*/
	DMediaDriver *iDriver;

	/**
	Mount information for the media device.
	
	@see TMountInfoData
	*/
	TMountInfoData iMountInfo;
	};

#ifdef __DEMAND_PAGING__
class DFragmentationPagingLock;
class DMediaPagingDevice;
#endif


/**
@publishedPartner
@released
The DPrimaryMedia base class which is derived from DMedia class is responsible for controlling the overall state of the media 
(for example whether the power is applied or the partition information has been determined and so on). 
Each media driver or extension that registers for a set of local drives also has to register for a set of DMedia objects at the same time.
This media set must contain just one primary media object. 
The driver that performs drive registration is responsible for creating the primary media object itself, 
which it then passes over to the local media sub-system for ownership. 
If further media objects are specified in the set, then the local media sub-system itself creates DMedia instances for these on behalf of the driver.
*/
class DPrimaryMediaBase : public DMedia
	{
public:
	enum TMsgId
		{
		EConnect=-1,
		EDisconnect=-2,
		};

	enum TForceMediaChangeFlags
		{
		/**
		Specifying zero as the flag for DPrimaryMediaBase::ForceMediaChange(), 
		results in all media drivers associated with the primary media being 
		closed and reopened.
		All pending requests on all logical drives associated with the primary 
		media will be cancelled.

		@see DPrimaryMediaBase::ForceMediaChange()
		@see RLocalDrive::ForceMediaChange()
		*/
		KForceMediaChangeReOpenAllMediaDrivers = 0,
		/**
		This flag is used to simulate ejecting and re-inserting the media.
		All pending requests on all logical drives associated with the primary 
		media will be cancelled.
		N.B. This is asynchronous in behaviour i.e. the caller will need to wait 
		for (two) media change notifications before the drive is ready for use

		@see DPBusPrimaryMedia::ForceMediaChange()
		@see RLocalDrive::ForceMediaChange()
		*/
		KMediaRemountForceMediaChange = 0x00000001,
		/**
		This flag is used to force the media driver for the specified logical 
		drive to be closed and reopened.
		It should not affect any pending requests on other logical drives 
		associated with the primary media.

		@see DPrimaryMediaBase::ForceMediaChange()
		@see RLocalDrive::ForceMediaChange()
		*/
		KForceMediaChangeReOpenMediaDriver = 0x80000000
		};

public:
	IMPORT_C DPrimaryMediaBase();
public:
	// provided by implementation
	IMPORT_C virtual TInt Create(TMediaDevice aDevice, TInt aMediaId, TInt aLastMediaId);
	IMPORT_C virtual TInt Connect(DLocalDrive* aLocalDrive);
	IMPORT_C virtual void Disconnect(DLocalDrive* aLocalDrive);
	IMPORT_C virtual TInt Request(TLocDrvRequest& aRequest);
	IMPORT_C virtual TInt QuickCheckStatus();
	IMPORT_C virtual TInt ForceMediaChange(TInt aMode);
	IMPORT_C virtual TInt InitiatePowerUp();
	IMPORT_C virtual TInt DoInCritical();
	IMPORT_C virtual void DoEndInCritical();
	IMPORT_C virtual void DeltaCurrentConsumption(TInt aCurrent);
	IMPORT_C virtual void DefaultDriveCaps(TLocalDriveCapsV2& aCaps);
	IMPORT_C virtual TBool IsRemovableDevice(TInt& aSocketNum);
public:
	// used by implementation
	IMPORT_C void NotifyMediaChange();
	IMPORT_C void NotifyPowerDown();
	IMPORT_C void NotifyEmergencyPowerDown();
	IMPORT_C void NotifyPsuFault(TInt anError);
	IMPORT_C void NotifyMediaPresent();
	IMPORT_C void PowerUpComplete(TInt anError);
public:
	IMPORT_C virtual void HandleMsg(TLocDrvRequest& aRequest);
	IMPORT_C virtual TInt DoRequest(TLocDrvRequest& aRequest);
	TInt OpenMediaDriver();
	void CloseMediaDrivers(DMedia* aMedia = NULL);
	void StartOpenMediaDrivers();
	void OpenNextMediaDriver();
	void DoOpenMediaDriverComplete(TInt anError);
	void DoPartitionInfoComplete(TInt anError);
	void CompleteCurrent(TInt anError);
	void CompleteRequest(TLocDrvRequest& aMsg, TInt aResult);
	IMPORT_C void RunDeferred();
	void SetClosed(TInt anError);
	void NotifyClients(TBool aMediaChange,TLocDrv* aLocDrv=NULL);
	TInt InCritical();
	void EndInCritical();
	void UpdatePartitionInfo();
	void MediaReadyHandleRequest();
	TInt SendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress = NULL);

#ifdef __DEMAND_PAGING__
	TInt PinSendReceive(TLocDrvRequest& aReq, TLinAddr aStart = NULL);
	TInt PinFragmentSendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress, TInt aLength);

	TBool PagingMediaPinAddress(TLinAddr aLinAddress, TInt aSize);
	void PagingMediaUnpinAddress();
#endif

#ifdef __DEMAND_PAGING__
	void RequestCountInc();
	void RequestCountDec();
#endif

public:
	TInt iLastMediaId;					/**< @internalComponent */
	TMessageQue iMsgQ;
	TDfcQue* iDfcQ;
	SDblQue iConnectionQ;				/**< @internalComponent */
	TMessageQue iDeferred;				/**< @internalComponent */
	TMessageQue iWaitMedChg;			/**< @internalComponent */
	TInt iState;						/**< @internalComponent */
	TInt iCritical;						/**< @internalComponent */
	TLocDrvRequest* iCurrentReq;
	TDfc iAsyncDfc;						/**< @internalComponent */
	TInt iAsyncErrorCode;				/**< @internalComponent */
	RPhysicalDeviceArray iPhysDevArray;	/**< @internalComponent */

	class DBody;
	DBody* iBody;						/**< @internalComponent */

	TInt iNextMediaId;					/**< @internalComponent */
	TInt iTotalPartitionsOpened;		/**< @internalComponent */
	TInt iMediaDriversOpened;			/**< @internalComponent */
	DMediaDriver* iNextMediaDriver;		/**< @internalComponent */


#ifdef __DEMAND_PAGING__
	// keep the size of class as it is used as base for PBus and may not want to bother building DP specific version.
	TUint8 iPagingMedia;				/**< @internalComponent */
	TUint8 iDataPagingMedia;			/**< @internalComponent */
	TUint8 iRomPagingMedia;				/**< @internalComponent */
	TUint8 iRunningDeferred;			/**< @internalComponent */
#else
	TInt iRunningDeferred;				/**< @internalComponent */
#endif
	};

#ifdef __DEMAND_PAGING__

/**
@internalComponent
@prototype
*/
NONSHARABLE_CLASS(DMediaPagingDevice) : public DPagingDevice
	{
public:
	enum TPagingRequestId
		{
		/** 
		Identifies any middle fragment of a Write request on a partition of a media that supports paging.
		@deprecated
		*/
		EWriteRequestFragment		=	DLocalDrive::EFirstReqNumberReservedForPaging,

		/** 
		Identifies the last fragment of a Write request on a partition of a media that supports paging.
		@deprecated
		*/
		EWriteRequestFragmentLast	=	DLocalDrive::EFirstReqNumberReservedForPaging+1,

		/** 
		Request for paging in (read) data from the ROM store area.
		*/
		ERomPageInRequest			=	DLocalDrive::EFirstReqNumberReservedForPaging+2,

		/** 
		Request for paging in (read) data from the code store area.
		*/
		ECodePageInRequest			=	DLocalDrive::EFirstReqNumberReservedForPaging+3,

        /**
        Provided to allow the following compile time assert.
        */
		EPagingRequestHighWaterMark
		};
    __ASSERT_COMPILE(EPagingRequestHighWaterMark <= DLocalDrive::ELastReqNumberReservedForPaging + 1);

	enum TQueue
		{
		EMainQ = 0x01,
		EDeferredQ=0x02
		};

public:
	DMediaPagingDevice(DPrimaryMediaBase* aPtr);
	virtual ~DMediaPagingDevice();
	
	// from DPagingDevice
	virtual TInt Read(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TInt aDrvNumber);
	virtual TInt Write(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize, TBool aBackground);
	virtual TInt DeleteNotify(TThreadMessage* aReq,TUint aOffset,TUint aSize);

	void CompleteRequest(TThreadMessage* aMsg, TInt aResult);
	void SendToMainQueueDfcAndBlock(TThreadMessage* aMsg);
	void SendToDeferredQ(TThreadMessage* aMsg);
	inline static TBool PageInRequest(TLocDrvRequest& aReq);
	inline static TBool PageOutRequest(TLocDrvRequest& aReq);
	inline static TBool PagingRequest(TLocDrvRequest& aReq);
public:
	TMessageQue iMainQ;
	TMessageQue iDeferredQ;
	DPrimaryMediaBase* iPrimaryMedia;

	TUint8 iEmptyingQ;
	TUint8 iDeleteNotifyNotSupported;
	TUint8 iSpare1;
	TUint8 iSpare2;

	TAny* iMountInfoDataLock;
	TAny* iMountInfoDescHdrLock;
	TAny* iMountInfoDescLenLock;

	TInt iFirstLocalDriveNumber;
	TInt iRomPagingDriveNumber;
	TInt iDataPagingDriveNumber;

	NFastMutex iInstrumentationLock;			// To protect instrumentation data

#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
	TUint8 iServicingROM;
	TUint8 iServicingCode;
	TUint8 iServicingDataIn;
	TUint8 iServicingDataOut;

	SMediaROMPagingConcurrencyInfo iROMStats;
	SMediaCodePagingConcurrencyInfo iCodeStats;
	SMediaDataPagingConcurrencyInfo iDataStats;
#endif

#ifdef __DEMAND_PAGING_BENCHMARKS__
	SPagingBenchmarkInfo iROMBenchmarkData;
	SPagingBenchmarkInfo iCodeBenchmarkData;
	SPagingBenchmarkInfo iDataInBenchmarkData;
	SPagingBenchmarkInfo iDataOutBenchmarkData;
	SMediaPagingInfo iMediaPagingInfo;
#endif
	};

inline TBool DMediaPagingDevice::PageInRequest(TLocDrvRequest& aReq)
	{
	return 
		(aReq.Flags() & TLocDrvRequest::EPaging) && 
		(aReq.Id() == ERomPageInRequest || 
		 aReq.Id() == ECodePageInRequest || 
		 aReq.Id() == DLocalDrive::ERead);}

inline TBool DMediaPagingDevice::PageOutRequest(TLocDrvRequest& aReq)
	{
	return 
		(aReq.Flags() & TLocDrvRequest::EPaging) && 
		(aReq.Id() == DLocalDrive::EWrite);}

inline TBool DMediaPagingDevice::PagingRequest(TLocDrvRequest& aReq)
	{
	return (aReq.Flags() & TLocDrvRequest::EPaging);
	}


/**
@internalComponent
@prototype
*/
class DFragmentationPagingLock: public DDemandPagingLock
	{
public:
	TInt Construct(TUint aNumPages);
	void Cleanup();
	void LockFragmentation()
		{
		__ASSERT_CRITICAL;
		__ASSERT_DEBUG(iFragmentationMutex, Kern::Fault("LOCMEDIA_H",__LINE__));
		// called in CS
		Kern::MutexWait(*iFragmentationMutex);
		}
	void UnlockFragmentation()
		{
		__ASSERT_CRITICAL;
		__ASSERT_DEBUG(iFragmentationMutex, Kern::Fault("LOCMEDIA_H",__LINE__));
		// called in CS
		Kern::MutexSignal(*iFragmentationMutex);
		}


public:
	TUint iFragmentGranularity;
private:
	DMutex* iFragmentationMutex; // to protect Kernel memory locking
	};
#endif //__DEMAND_PAGING__

/**
@publishedPartner
@released

An abstract base class for all media drivers in the local drive system.

All media drivers, whether associated with fixed media, such as the internal
drive, or removable media, such as a PC Card or MultiMediaCard, must define
and implement a class derived from this one.

An instance of this class is created by the media driver's PDD factory,
an instance of a class derived from DPhysicalDevice. 

@see DPhysicalDevice::Create()
@see DPhysicalDevice
*/
class DMediaDriver : public DBase
	{
public:
	IMPORT_C DMediaDriver(TInt aMediaId);
	IMPORT_C virtual ~DMediaDriver();
	IMPORT_C virtual void Close();
// Pure virtual
	IMPORT_C virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg);
	
	/**
	A function called by the local media subsystem to deal with a request, 
	and which must be implemented by the media driver.
	
	@param aRequest An object that encapsulates information about the request.
	
	@return A value indicating the result:
	        KErrNone, if the request has been sucessfully initiated;
	        KErrNotSupported, if the request cannot be handled by the device;
	        KMediaDriverDeferRequest, if the request cannot be handled
	        immediately because of an outstanding request (this request will be
	        deferred until the outstanding request has completed);
	        otherwise one of the other system-wide error codes.
	*/
	virtual TInt Request(TLocDrvRequest& aRequest)=0;

	/**
	A function called by the local media subsystem to get partition information
	for the media device.
	
	It is called once the subsystem has been notified that the media driver
	is open and has been succesfully initialised.
	
	This function must be implemented by the media driver.
	
	@param anInfo An object that, on successful return, contains
	              the partition information.
	
	@return KErrNone, if retrieval of partition information is to be
	        done asynchronously;
	        KErrCompletion, if retrieval of partition information has been
	        done synchronously, and successfully;
	        one of the other system-wide error codes, if retrieval of partition
	        information has been done synchronously, but unsuccessfully.
	*/
	virtual TInt PartitionInfo(TPartitionInfo &anInfo)=0;

	/**
	A function called by the local media subsystem to inform the media driver
	that the device should power down.
	
	This function must be implemented by the media driver.
	*/
	virtual void NotifyPowerDown()=0;

	/**
	A function called by the local media subsystem to inform the media driver
	that the device is to be immediately powered down.
	
    This function must be implemented by the media driver.
	*/
	virtual void NotifyEmergencyPowerDown()=0;
public:
	IMPORT_C void SetTotalSizeInBytes(Int64 aTotalSizeInBytes, TLocDrv* aLocDrv=NULL);
	IMPORT_C Int64 TotalSizeInBytes();
	IMPORT_C void SetCurrentConsumption(TInt aValue);
	IMPORT_C TInt InCritical();
	IMPORT_C void EndInCritical();
	IMPORT_C void Complete(TLocDrvRequest& aRequest, TInt aResult);
	IMPORT_C void OpenMediaDriverComplete(TInt anError);
	IMPORT_C void PartitionInfoComplete(TInt anError);
public:
	DPhysicalDevice* iPhysicalDevice;/**< @internalComponent */
	Int64 iTotalSizeInBytes;         /**< @internalComponent */
    TInt iCurrentConsumption;        /**< @internalComponent */
	DPrimaryMediaBase* iPrimaryMedia;/**< @internalComponent */
	TBool iCritical;                 /**< @internalComponent */
	TMountInfoData* iMountInfo;      /**< @internalComponent */
	};




/**
@publishedPartner
@released

A structure that a media driver may find useful in its implementation,
and is used to contain the information required when registering
the media driver with the Local Media Subsystem.

@see LocDrv::RegisterMediaDevice()
*/
struct SMediaDeviceInfo
	{
	
	/**
	The unique Media ID for a device.
	
    This can take one of the enumerated values defined
    by the TMediaDevice enum.
	*/
	TMediaDevice iDevice;
	
	
	/**
	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.
	*/
	TInt iDriveCount;
	
	
	/**
    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 iDriveCount.
	*/
	const TInt* iDriveList;
	
	
	/**
	Specifies the total number of DMedia objects to be associated with
	the media driver.
	
	This number includes the primary DPrimaryMedia object, plus all of
	the DMedia objects that are created for each additional drive, and
	which hold basic information about partitions.
	*/
	TInt iNumMedia; 
	
	
	/**
	A pointer to a descriptor containing the name of the media driver,
	for example: PCCard
	*/
	const TDesC* iDeviceName;
	};




/**
@publishedPartner
@released

A set of utility functions used in the management of local media drivers.
*/
class LocDrv
	{
public:
	IMPORT_C static TInt RegisterMediaDevice(TMediaDevice aDevice, TInt aDriveCount, const TInt* aDriveList, DPrimaryMediaBase* aPrimaryMedia, TInt aNumMedia, const TDesC& aName);
	IMPORT_C static TInt RegisterPasswordStore(TPasswordStore* aStore);
	IMPORT_C static TPasswordStore* PasswordStore();
#if !defined(__WINS__)
	IMPORT_C static TInt RegisterPagingDevice(DPrimaryMediaBase* aPrimaryMedia, const TInt* aPagingDriveList, TInt aDriveCount, TUint aPagingType, TInt aReadShift, TUint aNumPages);
#endif // __WINS__
	IMPORT_C static TInt RegisterDmaDevice(DPrimaryMediaBase* aPrimaryMedia,
										   TInt aMediaBlockSize, 
										   TInt aDmaMaxAddressable,
										   TInt aDmaAlignment);
	};

/**
@internalComponent
*/
inline TInt TLocDrv::Connect(DLocalDrive* aLocalDrive)
	{ return iPrimaryMedia->Connect(aLocalDrive); }

/**
@internalComponent
*/
inline void TLocDrv::Disconnect(DLocalDrive* aLocalDrive)
	{ iPrimaryMedia->Disconnect(aLocalDrive); }

/**
@internalComponent
*/
inline TInt TLocDrv::Request(TLocDrvRequest& aRequest)
	{ return iPrimaryMedia->Request(aRequest); }

/**
Returns the length of the media, in bytes, according to the partition information.

@return Total length of the media, in bytes.

@see	TPartitionInfo
*/
inline Int64 DMedia::MediaLenInBytes()
	{return(iPartitionInfo.iMediaSizeInBytes);}

/**
Returns the unique media ID for this device.

@return	The device ID that was set in the call to DMedia::Create().
		The return value will be one of the enumerators declared in TMediaDevice

@see	TMediaDevice
*/
inline TMediaDevice DMedia::DeviceType()
	{return(iDevice);}

/**
Returns the total number of partitions that exist on the media according to the
partition information.

This will always be less than or equal to KMaxPartitionEntries.

@return Number of partitions that exist on the media.

@see	KMaxPartitionEntries
@see	TPartitionInfo
*/
inline TInt DMedia::PartitionCount()
	{return(iPartitionInfo.iPartitionCount);}

/**
The start address of the partition, described as a relative offset, in bytes,
from the start of the media.

This value is used by the local media subsystem to calculate the absolute 
address on the media whenever an access such as a Read, Write or Format request
is made.

@param	aPartition	The partition whose start address is to be returned.

@return	The start address of the partition.

@see	TPartitionEntry
@see	TPartitionInfo
*/
inline Int64 DMedia::PartitionBaseAddr(TInt aPartition)
	{return(iPartitionInfo.iEntry[aPartition].iPartitionBaseAddr);}

/**
Returns the length of the partition, in bytes.

@param	aPartition	The partition whose length is to be returned.

@return	The length of the partition.

@see	TPartitionEntry
@see	TPartitionInfo
*/
inline Int64 DMedia::PartitionLen(TInt aPartition)
	{return(iPartitionInfo.iEntry[aPartition].iPartitionLen);}


/**
@internalTechnology

A utility class for scanning MBR/EBR partition tables.
*/
class TPartitionTableScanner
	{
public:
	enum {ESectorShift=9, ESectorSize=512};
	enum {EMaxNest=4};
	struct SPart
		{
		SPart(const TUint8* a);
		TUint8 iBootInd;
		TUint8 iType;
		TUint32 iRSS;
		TUint32 iSectors;
		};
	struct SEBR
		{
		TInt64 iRSS;
		TInt64 iSectors;
		};
public:
	IMPORT_C void Set(TUint8* aSectorBuffer, TPartitionEntry* aEntry, TInt aMaxPartitions, TInt64 aMediaSize);
	IMPORT_C TInt64 NextLBA();
	IMPORT_C TInt NumberOfPartitionsFound() const;
	TInt MakeEntry(const SPart& aP);
public:
	TInt64 iMediaSize;				// Total media size in sectors
	TInt64 iLBA;					// LBA currently in sector buffer
	TInt64 iFirstEBR;				// LBA of first EBR if any
	SEBR iStack[EMaxNest];
	TInt iStackPointer;
	TUint8* iSectorBuffer;			// Pointer to 512 byte area where sector data is stored
	TPartitionEntry* iFirstEntry;	// Where first scanned partition is stored
	TPartitionEntry* iNextEntry;	// Where next scanned partition will be stored
	TPartitionEntry* iLimit;		// iFirstEntry + max partitions
	};



#endif
