kerneltest/f32test/shostmassstorage/testclient/usbtestmsclient/drivemanager.cpp
changeset 0 a41df078684a
child 297 b2826f67641f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/shostmassstorage/testclient/usbtestmsclient/drivemanager.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,767 @@
+// Copyright (c) 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:
+// Class implementation of CDriveManager and CMassStorageDrive.
+// 
+//
+
+
+
+/**
+ @file
+ @internalTechnology
+*/
+
+#include <f32fsys.h>
+#include <e32property.h>
+
+
+#include "usbmsshared.h"
+#include "msctypes.h"
+
+#include "drivepublisher.h"
+#include "drivemanager.h"
+#include "debug.h"
+#include "msdebug.h"
+
+
+void TMediaParams::Init(TLocalDriveCapsV4& aCaps)
+    {
+    iSize = aCaps.MediaSizeInBytes();
+    TInt64 driveBlocks =  iSize / MAKE_TINT64(0, KDefaultBlockSize);
+    iNumBlocks = I64LOW(driveBlocks);
+    iMediaAtt = aCaps.iMediaAtt;
+    }
+
+
+void TLocalDriveRef::SetDriveState(TDriveState aState)
+    {
+    if (iDriveState != aState)
+        {
+        CMountCB* mount = iProxyDrive.Mount();
+        __ASSERT_DEBUG(mount != NULL, User::Invariant());
+        if (mount)
+            {
+            if (!IsActive(iDriveState) && IsActive(aState))
+                {
+                mount->IncLock();
+                }
+            else if (IsActive(iDriveState) && !IsActive(aState))
+                {
+                mount->DecLock();
+                }
+            __PRINT1(_L("SetDriveState: LockStatus=%d\n"), mount->LockStatus());
+            }
+
+        iDriveState = aState;
+        iDriveStateChangedPublisher.DriveStateChanged();
+        }
+    }
+
+
+TInt TLocalDriveRef::Read(const TInt64& aPos, TInt aLength, TDes8& aBuf, TBool aWholeMedia)
+	{
+    __MSFNLOG
+
+	TInt err = KErrUnknown; // never return this
+
+	if(aWholeMedia)
+		{
+		err = iProxyDrive.Read(aPos, aLength, &aBuf, KLocalMessageHandle, 0, RLocalDrive::ELocDrvWholeMedia);
+		}
+	else
+		{
+		err = iProxyDrive.Read(aPos, aLength, aBuf);
+		}
+
+	if (err == KErrLocked)
+		{
+		SetDriveState(TLocalDriveRef::ELocked);
+		}
+
+	return err;
+	}
+
+
+TInt TLocalDriveRef::Write(const TInt64& aPos, TDesC8& aBuf, TBool aWholeMedia)
+    {
+	TInt err = KErrNone;
+
+	TDriveState oldState = iDriveState;
+	if (oldState != EActive)
+        {
+		// SCSI hasn't called SetCritical
+		SetDriveState(EActive);
+		}
+
+	if (aWholeMedia)
+		{
+		err = iProxyDrive.Write(aPos, aBuf.Length(), &aBuf, KLocalMessageHandle, 0, RLocalDrive::ELocDrvWholeMedia);
+		}
+	else
+		{
+		err = iProxyDrive.Write(aPos,aBuf);
+		}
+
+	if (err == KErrLocked)
+		{
+		SetDriveState(ELocked);
+		}
+	else if (oldState != EActive)
+		{
+		SetDriveState(oldState);
+		}
+    return err;
+    }
+
+
+/**
+Checks the Media Changed flag, and optionally resets it.
+@return The state of the Media Changed flag.
+@param aReset If true, the Media Changed flag is reset to EFalse.
+*/
+TBool TLocalDriveRef::IsMediaChanged(TBool aReset)
+	{
+    __MSFNLOG
+	TBool mediaChanged = iMediaChanged;
+	if (aReset)
+        {
+	   	iMediaChanged = EFalse;
+	   	}
+	return mediaChanged;
+	}
+
+
+/**
+Set the Drive State to Active or Idle.
+@return KErrNone on success, KErrNotReady if media not present, KErrDisMounted if not mounted
+@param aCritical ETrue for Active, EFalse for Idle
+*/
+TInt TLocalDriveRef::SetCritical(TBool aCritical)
+	{
+    __MSFNLOG
+	TInt err = KErrNone;
+    if (iDriveState == EMediaNotPresent)
+		{
+		err = KErrNotReady;
+		}
+	else
+		{
+        SetDriveState(aCritical ? EActive : EIdle);
+		}
+	return err;
+	}
+
+
+/**
+Provides an interface to CProxyDrive::Caps that hides the
+package buffer.
+@return KErrNone on success, otherwise system wide error code
+@param aInfo
+*/
+TInt TLocalDriveRef::Caps(TLocalDriveCapsV4& aInfo)
+	{
+    __MSFNLOG
+	TLocalDriveCapsV4Buf buf;
+	buf.FillZ();
+
+	__PRINT(_L("CMassStorageDrive::DoCaps calling Caps\n"));
+	TInt err = iProxyDrive.Caps(buf);
+	__PRINT1(_L("CMassStorageDrive::DoCaps: Caps returned %d\n"), err);
+
+	if (err == KErrNone)
+		{
+		// Invoke function call operator to cast to TLocalDriveCapsV4&
+		aInfo = buf();
+		}
+
+	return err;
+	}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+@param aCritSec A Critical Section object shared by all drives.
+@param aDrives Reference to the list of CMassStorageDrive objects.
+@param aDriveMap Reference to array mapping lun to drive number for supported
+	   mass storage drives.
+@post Object is fully constructed
+ */
+CMassStorageDrive* CMassStorageDrive::NewL(RCriticalSection& aCritSec,
+                                           RDriveStateChangedPublisher& aDriveStateChangedPublisher)
+    {
+    __MSFNSLOG
+	CMassStorageDrive* self = new (ELeave) CMassStorageDrive(aCritSec, aDriveStateChangedPublisher);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+    }
+
+
+CMassStorageDrive::CMassStorageDrive(RCriticalSection& aCritSec,
+									 RDriveStateChangedPublisher& aDriveStateChangedPublisher)
+:   iCritSec(aCritSec),
+	iMountState(EDisconnected),
+	iDriveStateChangedPublisher(aDriveStateChangedPublisher)
+	{
+    __MSFNLOG
+	}
+
+
+void CMassStorageDrive::ConstructL()
+    {
+    __MSFNLOG
+    iDriveMediaErrorPublisher = new (ELeave) RDriveMediaErrorPublisher();
+    }
+
+
+CMassStorageDrive::~CMassStorageDrive()
+	{
+    __MSFNLOG
+    delete iDriveMediaErrorPublisher;
+	delete iLocalDrive;
+	}
+
+/**
+Read from the target drive unit.
+@return KErrNone on success, otherwise system wide error code
+*/
+TInt CMassStorageDrive::Read(const TInt64& aPos, TInt aLength, TDes8& aBuf, TBool aWholeMedia)
+	{
+    __MSFNLOG
+
+	TInt err = KErrUnknown; // never return this
+	iCritSec.Wait();
+
+	if(iMountState != EConnected)
+		{
+		err = KErrDisconnected;
+		}
+	else
+		{
+        err = iLocalDrive->Read(aPos, aLength, aBuf, aWholeMedia);
+		}
+
+	iCritSec.Signal();
+	return err;
+	}
+
+
+/**
+Write to the target drive unit.
+@return KErrNone on success, otherwise system wide error code
+*/
+TInt CMassStorageDrive::Write(const TInt64& aPos, TDesC8& aBuf, TBool aWholeMedia)
+	{
+    __MSFNLOG
+
+	TInt err = KErrNone;
+	iCritSec.Wait();
+
+	if (iMountState != EConnected)
+		{
+		err = KErrDisconnected;
+		}
+	else
+		{
+		__ASSERT_DEBUG(iLocalDrive, User::Invariant());
+        err = iLocalDrive->Write(aPos, aBuf, aWholeMedia);
+		}
+
+	iCritSec.Signal();
+	return err;
+	}
+
+
+/**
+Provides an interface to CProxyDrive::Caps that hides the
+package buffer.
+@return KErrNone on success, otherwise system wide error code
+@param aInfo
+*/
+TInt CMassStorageDrive::DoCaps(TLocalDriveCapsV4& aInfo)
+	{
+    __MSFNLOG
+    TInt err = KErrDisMounted;
+
+    if (iLocalDrive)
+        {
+        err = iLocalDrive->Caps(aInfo);
+        }
+	return err;
+	}
+
+
+/**
+Publish media error, user should reinsert the memory card.
+Similar to FAT32's TDriver::HandleCriticalError.
+Note: User notification is not implemented, instead we abort and dismount.
+*/
+TInt CMassStorageDrive::HandleCriticalError()
+	{
+    __MSFNLOG
+	TRAPD(err, iDriveMediaErrorPublisher->PublishErrorL(ETrue));
+    // ignore leave
+    err = err;
+	return KErrAbort;
+	}
+
+
+TInt CMassStorageDrive::ClearCriticalError()
+	{
+    __MSFNLOG
+	TRAPD(err, iDriveMediaErrorPublisher->PublishErrorL(EFalse));
+    // ignore leave
+    err = err;
+	return KErrNone;
+	}
+
+
+/**
+Checks the Media Changed flag, and optionally resets it.
+@return The state of the Media Changed flag.
+@param aReset If true, the Media Changed flag is reset to EFalse.
+*/
+TBool CMassStorageDrive::IsMediaChanged(TBool aReset)
+	{
+    __MSFNLOG
+
+	iCritSec.Wait();
+
+	TBool mediaChanged = EFalse;
+	if (iLocalDrive)
+		{
+		mediaChanged = iLocalDrive->IsMediaChanged(aReset);
+        }
+
+	iCritSec.Signal();
+
+	__PRINT1(_L("CMassStorageDrive::IsMediaChanged: returning %d\n"), mediaChanged);
+	return mediaChanged;
+	}
+
+/**
+Set the Drive State to Active or Idle.
+@return KErrNone on success, KErrNotReady if media not present, KErrDisMounted if not mounted
+@param aCritical ETrue for Active, EFalse for Idle
+*/
+TInt CMassStorageDrive::SetCritical(TBool aCritical)
+	{
+    __MSFNLOG
+
+	TInt err = KErrDisMounted;
+	iCritSec.Wait();
+	if (iLocalDrive)
+		{
+        err = iLocalDrive->SetCritical(aCritical);
+		}
+
+	iCritSec.Signal();
+	return err;
+	}
+
+/**
+Set the mount state
+*/
+void CMassStorageDrive::SetMountConnectedL(CProxyDrive& aProxyDrive,
+                                           TBool& aMediaChanged,
+                                           RDriveStateChangedPublisher& aDriveStateChangedPublisher)
+	{
+    __MSFNLOG
+	TLocalDriveRef* localDrive = NULL;
+
+	__PRINT(_L("SetMountConnectedL entering critical section\n"));
+	iCritSec.Wait(); // note: signalled in SetMountState
+
+   	TRAPD(err, localDrive = new (ELeave) TLocalDriveRef(aProxyDrive,
+                                                        aMediaChanged,
+                                                        aDriveStateChangedPublisher));
+   	if (err)
+   		{
+   		iCritSec.Signal();
+   		User::Leave(err);
+   		}
+	iLocalDrive = localDrive;
+	SetMountState(EConnected, ETrue);
+	}
+
+/**
+@return KErrNone
+@param aNewState
+@param aLocalDrive Only provide this if aNewState is EConnected.
+*/
+void CMassStorageDrive::SetMountState(TMountState aNewState, TBool aCriticalSection/*=EFalse*/)
+	{
+    __MSFNLOG
+	if(iMountState == aNewState)
+		{
+		__PRINT(_L("SetMountState: No change\n"));
+		}
+	else
+		{
+		// If called from SetMountConnected, already in critical section,
+        // otherwise, must enter it here.
+        if (!aCriticalSection)
+            {
+			iCritSec.Wait();
+            }
+
+		switch(aNewState)
+			{
+			case EDisconnected:
+				delete iLocalDrive;
+				iLocalDrive = NULL;
+				break;
+
+			case EConnected:
+			case EDisconnecting:
+			case EConnecting:
+				// Do not change iLocalDrive for these state changes
+				break;
+			}
+
+		iMountState = aNewState;
+		__PRINT1(_L("SetMountState: state=%d\n"), iMountState);
+
+		iDriveStateChangedPublisher.DriveStateChanged();
+		iCritSec.Signal();
+		__PRINT(_L("SetMountState has left the critical section\n"));
+		}
+	}
+
+/**
+@return Current drive media state
+*/
+TLocalDriveRef::TDriveState CMassStorageDrive::DriveState() const
+	{
+    __MSFNSLOG
+	return iLocalDrive ? iLocalDrive->DriveState() : TLocalDriveRef::EErrDisMounted;
+	}
+
+/**
+Check for media not present, and return the drive state.
+@return Current drive media state
+*/
+TLocalDriveRef::TDriveState CMassStorageDrive::CheckDriveState()
+	{
+    __MSFNLOG
+	TLocalDriveRef::TDriveState state = TLocalDriveRef::EErrDisMounted;
+	iCritSec.Wait();
+
+	if (iLocalDrive)
+		{
+		TInt err = KErrGeneral;
+        TLocalDriveCapsV4 caps;
+
+		FOREVER
+			{
+			// Initialise in case Caps() fails
+			caps.iType = ::EMediaNotPresent;
+			err = DoCaps(caps);
+
+			__PRINTERR(_L("CheckDriveState: DoCaps err=%d\n"), err);
+			if (err == KErrNotReady || (err == KErrNone && caps.iType == ::EMediaNotPresent))
+				{
+				__PRINT(_L("CheckDriveState: detected MediaNotPresent\n"));
+
+				SetDriveState(TLocalDriveRef::EMediaNotPresent);
+
+				if (HandleCriticalError() == KErrAbort)
+					break;
+				}
+			else
+				{
+				ClearCriticalError();
+				break;
+				}
+			}
+
+		if (err == KErrNone && caps.iType != ::EMediaNotPresent)
+			{
+            iMediaParams.Init(caps);
+            TLocalDriveRef::TDriveState driveState = TLocalDriveRef::EIdle;
+
+			if (iLocalDrive->DriveState() == TLocalDriveRef::EMediaNotPresent)
+				{
+				__PRINT(_L("CheckDriveState: detected media inserted\n"));
+				}
+			else if (iLocalDrive->DriveState() == TLocalDriveRef::ELocked &&
+					 !(caps.iMediaAtt & KMediaAttLocked))
+				{
+				__PRINT(_L("CheckDriveState: detected media unlocked\n"));
+				}
+			else if (caps.iMediaAtt & KMediaAttLocked)
+				{
+				__PRINT(_L("CheckDriveState: detected media locked\n"));
+				driveState = TLocalDriveRef::ELocked;
+				}
+            SetDriveState(driveState);
+			}
+
+		// Get the current state
+		state = iLocalDrive->DriveState();
+		}
+
+	iCritSec.Signal();
+
+	return state;
+	}
+
+
+/**
+@param aNewState
+*/
+void CMassStorageDrive::SetDriveState(TLocalDriveRef::TDriveState aNewState)
+	{
+    __MSFNLOG
+	__ASSERT_DEBUG(aNewState == TLocalDriveRef::EIdle ||
+                   (iMountState == EConnected && NULL != iLocalDrive) ||
+                   (iMountState == EDisconnecting && NULL != iLocalDrive),
+        User::Invariant());
+
+	if (!iLocalDrive)
+		{
+		__PRINT(_L("SetDriveState: Drive not mounted.\n"));
+		}
+	else
+		{
+        iLocalDrive->SetDriveState(aNewState);
+		__PRINT2(_L("SetDriveState: %d->%d\n"), iLocalDrive->iDriveState, aNewState);
+		}
+	}
+
+
+/////////////////////////////////////////////////////////////////
+
+/**
+Construct a CDriveManager object.
+@param aDriveMap Reference to array mapping lun to drive number for supported
+	   mass storage drives.
+*/
+CDriveManager* CDriveManager::NewL(const TLunToDriveMap& aDriveMap)
+	{
+    __MSFNSLOG
+	__PRINT1(_L("CDriveManager::NewL - %d drives\n"), aDriveMap.Count());
+
+	CDriveManager* self = new (ELeave) CDriveManager(aDriveMap.Count() -1);
+	CleanupStack::PushL(self);
+	self->ConstructL(aDriveMap);
+	CleanupStack::Pop();
+	return self;
+	}
+
+CDriveManager::CDriveManager(TLun aMaxLun)
+:   iMaxLun(aMaxLun)
+	{
+    __MSFNLOG
+    }
+
+/**
+Construct a CDriveManager object.
+*/
+void CDriveManager::ConstructL(const TLunToDriveMap& aDriveMap)
+	{
+    __MSFNLOG
+	User::LeaveIfError(iDriveCritSec.CreateLocal());
+
+    iDriveStateChangedPublisher = new (ELeave) RDriveStateChangedPublisher(iDrives, aDriveMap);
+
+    iDrives.Reserve(iMaxLun + 1);
+
+	for (TLun lun = 0; lun < iMaxLun + 1; lun++)
+		{
+		iDrives.Append(CMassStorageDrive::NewL(iDriveCritSec,
+                                               *iDriveStateChangedPublisher));
+		}
+
+	// Publish initial drive state
+	if (iDrives.Count() > 0)
+		{
+		iDriveStateChangedPublisher->DriveStateChanged();
+		}
+	}
+
+/**
+Destructor
+*/
+CDriveManager::~CDriveManager()
+	{
+    __MSFNLOG
+	iDrives.ResetAndDestroy();
+	delete iDriveStateChangedPublisher;
+	iDriveCritSec.Close();
+	}
+
+/**
+Set the mount state to Connected and specify the Proxy Drive.
+@return KErrNone on success, otherwise system wide error code
+@param aDrive The mounted Proxy Drive
+@param aLun The Logical Drive Unit identifier (0..numDrives-1)
+@pre If the Mount State is Connected, then aDrive must be the
+     same as it was the last time this function was called.
+@post The Mount State will be Connected.
+*/
+void CDriveManager::RegisterDriveL(CProxyDrive& aProxyDrive, TBool& aMediaChanged, TLun aLun)
+	{
+    __MSFNLOG
+	__PRINT1(_L("Lun=%d \n"),aLun);
+	CMassStorageDrive* drive = Drive(aLun);
+	drive->SetMountConnectedL(aProxyDrive, aMediaChanged, *iDriveStateChangedPublisher);
+	}
+
+/**
+Set the mount state to Disconnected.
+@return KErrNone on success, otherwise system wide error code
+@param aLun The Logical Drive Unit identifier (0..numDrives-1)
+@post The Mount State will be Disconnected.
+*/
+void CDriveManager::DeregisterDrive(TLun aLun)
+	{
+    __MSFNLOG
+    CMassStorageDrive* drive = Drive(aLun);
+	drive->SetMountDisconnected();
+	}
+
+/**
+Return a pointer to the drive specified aLun, or NULL if aLun is invalid.
+
+@return Pointer to the specified drive, or NULL.
+@param aLun The Logical Drive Unit identifier (0..numDrives-1)
+@param aError KErrNone on success, KErrArgument if NULL is returned.
+*/
+CMassStorageDrive* CDriveManager::Drive(TLun aLun) const
+	{
+    __MSFNSLOG
+	__ASSERT_DEBUG(aLun < iDrives.Count(), User::Invariant());
+    return iDrives[aLun];
+	}
+
+/**
+Checks the Media Changed flag, and optionally resets it.
+@return The state of the Media Changed flag.
+@param aLun The Logical Drive Unit identifier (0..numDrives-1)
+@param aReset If true, the Media Changed flag is reset to EFalse.
+*/
+TBool CDriveManager::IsMediaChanged(TLun aLun, TBool aReset)
+	{
+    __MSFNLOG
+	CMassStorageDrive* drive = Drive(aLun);
+	return drive->IsMediaChanged(aReset);
+	}
+
+/**
+Set the Drive State to Active or Idle.
+Ref: 3.6.3.2 - PREVENT_MEDIUM_REMOVAL
+@return KErrNone on success, otherwise system wide error code
+@param aLun The Logical Drive Unit identifier (0..numDrives-1)
+@param aCritical ETrue for Active, EFalse for Idle
+*/
+TInt CDriveManager::SetCritical(TLun aLun, TBool aCritical)
+	{
+    __MSFNLOG
+	TInt err = KErrUnknown; // never return this
+
+	TLun i = aLun;
+	TLun cnt = aLun + 1;
+
+	if (aLun == KAllLuns)
+		{
+		i = 0;
+		cnt = iMaxLun + 1;
+		}
+
+	for(; i < cnt; i++)
+		{
+		CMassStorageDrive* drive = Drive(i);
+		err = drive->SetCritical(aCritical);
+		}
+	return err;
+	}
+
+void CDriveManager::Connect()
+	{
+	__FNLOG("CDriveManager::Connect");
+    TLun lun = iMaxLun;
+    do
+        {
+        Connect(lun);
+        }
+    while(--lun >= 0);
+    }
+
+/**
+Inititiate transition to Connected.
+@return KErrNone on success, otherwise system wide error code
+@param aLun The Logical Drive Unit identifier (0..numDrives-1)
+@post The Mount State will be Connected or Connecting.
+*/
+void CDriveManager::Connect(TLun aLun)
+	{
+    __MSFNLOG
+	CMassStorageDrive* drive = Drive(aLun);
+
+	__PRINT2(_L("CDriveManager::Connect lun=%d, mountState=%d\n"), aLun, drive->MountState());
+
+   	switch(drive->MountState())
+   		{
+ 	case CMassStorageDrive::EDisconnected:
+ 		drive->SetMountConnecting();
+ 		break;
+ 	case CMassStorageDrive::EDisconnecting:
+ 		drive->SetMountConnected();
+ 		break;
+ 	case CMassStorageDrive::EConnected:
+ 	case CMassStorageDrive::EConnecting:
+    default:
+ 		// do nothing
+ 		break;
+		}
+	}
+
+void CDriveManager::Disconnect()
+	{
+	__FNLOG("CDriveManager::Disconnect");
+    TLun lun = iMaxLun;
+    do
+        {
+        Disconnect(lun);
+        }
+    while(--lun >= 0);
+    }
+
+/**
+Inititiate transition to Disconnected.
+@return KErrNone on success, otherwise system wide error code
+@param aLun The Logical Drive Unit identifier (0..numDrives-1)
+@post The Mount State will be Disconnected or Disconnecting.
+*/
+void CDriveManager::Disconnect(TLun aLun)
+	{
+    __MSFNLOG
+	CMassStorageDrive* drive = Drive(aLun);
+   	switch (drive->MountState())
+   		{
+   	case CMassStorageDrive::EConnected:
+   		drive->SetMountDisconnecting();
+   		break;
+   	case CMassStorageDrive::EConnecting:
+   		drive->SetMountDisconnected();
+   		break;
+   	case CMassStorageDrive::EDisconnected:
+   	case CMassStorageDrive::EDisconnecting:
+   		// do nothing
+   		break;
+   		}
+	}