userlibandfileserver/fileserver/shostmassstorage/server/controller/cusbhostmsdevicethread.cpp
changeset 43 96e5fb8b040d
child 44 36bfc973b146
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/shostmassstorage/server/controller/cusbhostmsdevicethread.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,425 @@
+// Copyright (c) 2008-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:
+// Implements a Session of a Symbian OS server for the RUsbMassStorage API
+//
+//
+
+/**
+ @file
+ @internalTechnology
+*/
+
+#include <e32base.h>
+
+#include "msctypes.h"
+#include "shared.h"
+#include "msgservice.h"
+#include "cusbhostmslogicalunit.h"
+#include "cusbhostmsdevice.h"
+#include "msdebug.h"
+#include "cusbhostmssession.h"
+#include "cusbhostmsdevicethread.h"
+#include "debug.h"
+
+/**
+Constructor
+*/
+TDeviceHandler::TDeviceHandler(CUsbHostMsDevice& aDevice)
+:   iDevice(aDevice)
+    {
+    __MSFNLOG
+    }
+
+
+/**
+   Services messages directed to a device. Messages associated with a single
+   Logical Unit contained by the device are forwarded to the Logical Unit
+   Handler.
+
+   @param aMessage
+ */
+void TDeviceHandler::HandleMessageL(const RMessage2& aMessage)
+    {
+    __MSFNLOG
+    TLun lun = iDevice.GetAndSetLunL(aMessage);
+
+	switch (aMessage.Function())
+		{
+	case EUsbHostMsSuspendLun:
+        iDevice.SuspendLunL(lun);
+		break;
+    case EUsbHostMsUnRegisterLun:
+        iDevice.RemoveLunL(lun);
+        break;
+    default:
+        // Try Logical Unit Handler
+        CUsbHostMsLogicalUnit& lu = iDevice.GetLuL(lun);
+        TLogicalUnitHandler luHandler(lu);
+        luHandler.HandleMessageL(aMessage);
+		break;
+		}
+    }
+
+
+/**
+   Constructor
+
+   @param aLu Reference to the logical unit object
+ */
+TLogicalUnitHandler::TLogicalUnitHandler(CUsbHostMsLogicalUnit& aLu)
+:   iLu(aLu)
+    {
+    __MSFNLOG
+    }
+
+
+/**
+   Services messages directed to a specific Logical Unit. Unrecognized messages
+   will cause a PANIC.
+
+   @param aMessage
+ */
+void TLogicalUnitHandler::HandleMessageL(const RMessage2& aMessage)
+	{
+    __MSFNLOG
+	switch (aMessage.Function())
+		{
+	case EUsbHostMsNotifyChange:
+        iLu.NotifyChange(aMessage);
+		break;
+	case EUsbHostMsCancelChangeNotifier:
+        iLu.CancelChangeNotifierL();
+		break;
+	case EUsbHostMsForceRemount:
+        iLu.ForceCompleteNotifyChangeL();
+		break;
+	case EUsbHostMsRead:
+        iLu.ReadL(aMessage);
+		break;
+	case EUsbHostMsWrite:
+        iLu.WriteL(aMessage);
+		break;
+	case EUsbHostMsErase:
+        iLu.EraseL(aMessage);
+		break;
+	case EUsbHostMsCapacity:
+        iLu.CapsL(aMessage);
+		break;
+	default:
+		aMessage.Panic(KUsbHostMsSrvPncCat, EUsbMsPanicIllegalIPC);
+		break;
+		}
+	}
+
+
+void CUsbHostMsDeviceThread::DoStartServerL(TAny* aPtr)
+    {
+    __MSFNSLOG
+    CActiveScheduler* s = new(ELeave) CActiveScheduler;
+    CActiveScheduler::Install(s);
+
+	CUsbHostMsDeviceThread* iThread = (CUsbHostMsDeviceThread*)aPtr;
+	CActiveScheduler::Add(iThread);
+
+    iThread->Start();
+
+	RThread::Rendezvous(KErrNone);
+
+	//
+    // Ready to run
+    CActiveScheduler::Start();
+
+    //
+    // Cleanup the scheduler
+	delete s;
+    }
+
+
+TInt CUsbHostMsDeviceThread::Entry(TAny* aPtr)
+	{
+    __MSFNSLOG
+	CTrapCleanup* cleanup = CTrapCleanup::New();
+    if (!cleanup)
+        {
+        return KErrNoMemory;
+        }
+
+    TRAPD(error, DoStartServerL(aPtr));
+    delete cleanup;
+    return error;
+	}
+
+
+void  CUsbHostMsDeviceThread::RunL()
+	{
+    __MSFNLOG
+
+    // called on completion of MessageRequest() or Resume()
+    User::LeaveIfError(iStatus.Int());
+
+	Lock();    
+    if (iUsbHostMsDevice)
+        {
+        if (iUsbHostMsDevice->IsSuspended())
+            {
+            // request resume 
+            Unlock();
+            iUsbHostMsDevice->Resume(iStatus);
+            SetActive();
+            return;
+            }
+        }
+
+    // process message queue
+    RMessage2 msg = iRMessage2[iDequeueIndex];
+
+    iDequeueIndex++;
+
+    if(iDequeueIndex >= KMaxNumMessage)
+     	iDequeueIndex = 0;
+    if(iQueueFull)
+     	iQueueFull = EFalse;
+
+    HandleMessage(msg);
+
+    if ((iQueueIndex != iDequeueIndex) || iQueueFull)
+	   	{
+        // self completion        
+        TRequestStatus* status = &iStatus;
+        User::RequestComplete(status, KErrNone);
+        SetActive();
+        }
+    else
+        {
+        iUsbHostMsSession.MessageRequest(iStatus);
+        SetActive();
+        }
+    Unlock();
+	}
+
+
+void CUsbHostMsDeviceThread::DoCancel()
+    {
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete(status, KErrCancel);
+    }
+
+
+TInt CUsbHostMsDeviceThread::RunError(TInt aError)
+{
+    __HOSTPRINT1(_L(">> HOST RunError returning %d"), aError);
+    return KErrNone;
+}
+
+
+TInt CUsbHostMsDeviceThread::QueueMsg(const RMessage2& aMsg)
+	{
+    __MSFNLOG
+
+	if (iQueueFull)
+		{
+		return KErrOverflow;
+		}
+
+    Lock();
+
+	iRMessage2[iQueueIndex] = aMsg;
+	iQueueIndex++;
+
+	if (iQueueIndex >= KMaxNumMessage)
+		{
+		iQueueIndex = 0;
+		}
+
+	if (iQueueIndex == iDequeueIndex)
+		{
+		iQueueFull = ETrue;
+		}
+	Unlock();
+	return KErrNone;
+	}
+
+
+CUsbHostMsDeviceThread::CUsbHostMsDeviceThread(CUsbHostMsSession& aUsbHostMsSession, TUint aToken)
+:	CActive(EPriorityStandard),
+    iUsbHostMsSession(aUsbHostMsSession),
+    iQueueFull(EFalse)
+	{
+    __MSFNLOG
+    TBuf<30> nameBuf;
+    nameBuf.Format(_L("Host Ms ThreadMutex%d"), aToken);
+	iMutex.CreateGlobal(nameBuf,EOwnerProcess);
+	}
+
+CUsbHostMsDeviceThread::~CUsbHostMsDeviceThread()
+	{
+    __MSFNLOG
+    Cancel();
+	iMutex.Close();
+	}
+
+CUsbHostMsDeviceThread* CUsbHostMsDeviceThread::NewL(CUsbHostMsSession& aUsbHostMsSession, TUint aToken)
+	{
+    __MSFNSLOG
+	CUsbHostMsDeviceThread* r = new (ELeave) CUsbHostMsDeviceThread(aUsbHostMsSession, aToken);
+	return r;
+	}
+
+
+void CUsbHostMsDeviceThread::Start()
+    {
+    iUsbHostMsSession.MessageRequest(iStatus);
+    SetActive();
+    }
+
+
+/**
+ Handles the request (in the form of a message) received from the client
+@param	aMessage	The received message
+ */
+void CUsbHostMsDeviceThread::HandleMessage(const RMessage2& aMessage)
+	{
+    __MSFNLOG
+	TInt ret = KErrNotReady;
+    __HOSTPRINT2(_L(">> HOST DispatchMessageL Function=%d %d"), aMessage.Function(), aMessage.Int3());
+	switch (aMessage.Function())
+		{
+	case EUsbHostMsRegisterInterface:
+		TRAP(ret, RegisterInterfaceL(aMessage));
+		break;
+    case EUsbHostMsInitialiseInterface:
+		TRAP(ret, InitialiseInterfaceL(aMessage));
+        // CUsbInterfaceHandler::GetMaxLun() completes asynchronously
+        if (ret)
+            {
+            // Error condition needs to be completed
+            break;
+            }
+		return;
+	case EUsbHostMsUnRegisterInterface:
+		TRAP(ret, UnRegisterInterfaceL(aMessage));
+		break;
+	case EUsbHostMsRegisterLun:
+		TRAP(ret, RegisterLogicalUnitL(aMessage));
+		break;
+	case EUsbHostMsGetNumLun:
+		TRAP(ret, GetNumLunL(aMessage));
+		break;
+	case EUsbHostMsShutdown:
+		ret = Shutdown();
+		break;
+    default:
+        // Try Device Handler and Logical Unit Handler
+        __ASSERT_DEBUG(iUsbHostMsDevice, User::Invariant());
+        TDeviceHandler deviceHandler(*iUsbHostMsDevice);
+        TRAP(ret, deviceHandler.HandleMessageL(aMessage));
+		break;
+		}
+    __HOSTPRINT1(_L(">> HOST returning %d"), ret);
+
+    if (aMessage.Function() != EUsbHostMsNotifyChange)
+        {
+        aMessage.Complete(ret);
+        }
+	}
+
+
+/**
+Client request to shut down the server
+
+return KErrNone
+*/
+TInt CUsbHostMsDeviceThread::Shutdown()
+    {
+    __MSFNLOG
+    CActiveScheduler::Stop();
+	return KErrNone;
+	}
+
+void CUsbHostMsDeviceThread::GetNumLunL(const RMessage2& aMessage)
+	{
+	__MSFNLOG
+    if (!iUsbHostMsDevice)
+        {
+        User::Leave(KErrNotReady);
+        }
+
+	TUint32 maxLun = iUsbHostMsDevice->GetMaxLun() + 1;
+	TPtrC8 pLun((TUint8*)&maxLun,sizeof(TUint32));
+	aMessage.WriteL(0,pLun);
+	}
+
+
+void CUsbHostMsDeviceThread::RegisterInterfaceL(const RMessage2& aMessage)
+	{
+	__MSFNLOG
+
+	THostMassStorageConfig msDeviceConfig;
+	TPtr8 ptr((TUint8*)&msDeviceConfig,sizeof(THostMassStorageConfig));
+	aMessage.ReadL(0, ptr);
+
+    __HOSTPRINT1(_L("RegisterInterfaceL Token=%d "), msDeviceConfig.iInterfaceToken);
+
+	iUsbHostMsDevice = CUsbHostMsDevice::NewL(msDeviceConfig);
+	}
+
+
+void CUsbHostMsDeviceThread::InitialiseInterfaceL(const RMessage2& aMessage)
+	{
+	__MSFNLOG
+    if (!iUsbHostMsDevice)
+        {
+        User::Leave(KErrNotReady);
+        }
+
+	TRAPD(err, iUsbHostMsDevice->InitialiseL(aMessage));
+    if (err != KErrNone)
+        {
+        delete iUsbHostMsDevice;
+		iUsbHostMsDevice = NULL;
+        User::Leave(err);
+        }
+	}
+
+
+void CUsbHostMsDeviceThread::UnRegisterInterfaceL(const RMessage2& aMessage)
+    {
+    __MSFNLOG
+    if (!iUsbHostMsDevice)
+        {
+        User::Leave(KErrNotReady);
+        }
+
+	TRAPD(err, iUsbHostMsDevice->UnInitialiseL());
+	delete iUsbHostMsDevice;
+	iUsbHostMsDevice = NULL;
+    User::LeaveIfError(err);
+    }
+
+
+void CUsbHostMsDeviceThread::RegisterLogicalUnitL(const RMessage2& aMessage)
+	{
+    if (!iUsbHostMsDevice)
+        {
+        User::Leave(KErrNotReady);
+        }
+
+	TUint32 iLunId = aMessage.Int0() + 1; // Subssessions need a positive value to store in the handles. We represent Luns as LunId+1
+	TPtrC8 pLun((TUint8*)&iLunId, sizeof(TUint32));
+	aMessage.WriteL(3, pLun);
+	iLunId -= 1;	// We represent LunId in MSC from 0 to MaxLun-1 as represented in BOT
+	iUsbHostMsDevice->AddLunL(iLunId);
+	iUsbHostMsDevice->InitLunL(iLunId);
+	}
+