usbmgmt/usbmgr/device/classdrivers/ncm/classcontroller/src/ncmclasscontroller.cpp
branchRCL_3
changeset 15 f92a4f87e424
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/device/classdrivers/ncm/classcontroller/src/ncmclasscontroller.cpp	Tue Aug 31 17:01:47 2010 +0300
@@ -0,0 +1,397 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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: 
+*
+*/
+
+/**
+ * @file
+ * @internalComponent
+ */
+
+#include <usb_std.h>
+#include <barsc.h>
+#include <barsread.h>
+#include <cusbclasscontrollerbase.h> 
+#include <musbclasscontrollernotify.h>
+#include <usb/usbncm.h>
+#include <random.h>
+
+#include "ncmclasscontroller.h"
+#include "ncmconnectionmanager.h"
+#include "ncmclientmanager.h"
+
+// For OST tracing
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "ncmclasscontrollerTraces.h"
+#endif
+
+
+using namespace UsbNcm;
+_LIT(KNcmControllerPanic, "UsbNcmCC"); // must be <=16 chars
+const TInt KNcmStartupPriority = 3;
+
+// MTU size. 
+extern const TUint KEthernetFrameSize = 8192;
+
+// Lengths of the various bits of the NCM descriptor. Taken from the NCM Specification rev 1.0.
+const TInt KNcmInterfaceDescriptorLength = 3;
+const TInt KNcmCcHeaderDescriptorLength = 5;
+const TInt KNcmFunctionalDescriptorLength = 4;
+const TInt KNcmCcUfdDescriptorLength = 5;
+const TInt KNcmDataClassHeaderDescriptorLength = 5;
+const TInt KNcmDeviceDescriptorLength = 18;
+const TInt KNcmConfigurationDescriptorLength = 9;
+const TInt KNcmCommunicationClassEndpointOutDescriptorLength = 9;
+const TInt KNcmNotificationEndpointDescriptorLength = 7;
+const TInt KNcmDataClassInterfaceDescriptorLength = 9;
+const TInt KNcmDataClassEndpointInDescriptorLength = 7;
+const TInt KNcmDataClassEndpointOutDescriptorLength = 7;
+
+const TInt KNcmDescriptorLength = KNcmInterfaceDescriptorLength
+        + KNcmCcHeaderDescriptorLength + KNcmFunctionalDescriptorLength
+        + KNcmCcUfdDescriptorLength + KNcmDataClassHeaderDescriptorLength
+        + KNcmDeviceDescriptorLength + KNcmConfigurationDescriptorLength
+        + KNcmCommunicationClassEndpointOutDescriptorLength
+        + KNcmNotificationEndpointDescriptorLength
+        + KNcmDataClassInterfaceDescriptorLength
+        + KNcmDataClassEndpointInDescriptorLength
+        + KNcmDataClassEndpointOutDescriptorLength;
+
+// Panic codes
+enum TNcmClassControllerPanicCode
+    {
+    ENcmPanicBadState = 1,
+    ENcmPanicOutstandingRequestFromDevice,
+    ENcmPanicAlreadyActive,
+    ENcmPanicUnhandledError,
+    ENcmPanicBadApiCallStart, // Attempt to call Start() when in illegal state
+    ENcmPanicBadApiCallStop, // Attempt to call Stop() when in illegal state
+    ENcmPanicUnexpectedIapState,
+    ENcmPanicUnexpectedError
+    };
+
+/**
+ * Constructs a CNcmClassController object.
+ * @param aOwner USB Device that owns and manages the class
+ * @return Ownership of a new CNcmClassController object
+ */
+CNcmClassController* CNcmClassController::NewL(
+        MUsbClassControllerNotify & aOwner)
+    {
+    OstTraceFunctionEntry0( CNCMCLASSCONTROLLER_NEWL_ENTRY );
+
+    CNcmClassController* self =
+            new (ELeave) CNcmClassController(aOwner);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_NEWL_EXIT, ( TUint )( self ) );
+    return self;
+    }
+
+/**
+ * Constructor.
+ * @param aOwner USB Device that owns and manages the class
+ */
+CNcmClassController::CNcmClassController(
+        MUsbClassControllerNotify& aOwner) :
+    CUsbClassControllerPlugIn(aOwner, KNcmStartupPriority)
+    {
+    OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_ENTRY, this );
+    
+    iState = EUsbServiceIdle; // needs explicit initialisation as non-zero
+    
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_EXIT, this );
+    }
+
+/**
+ * Method to perform second phase construction.
+ */
+void CNcmClassController::ConstructL()
+    {
+    OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_CONSTRUCTL_ENTRY, this );
+    
+#ifndef OVERDUMMY_NCMCC
+    TInt err = KErrNone;
+    
+    OstTrace0(TRACE_NORMAL, CNCMCLASSCONTROLLER_CONSTRUCTL, "About to load eusbcsc!");
+    _LIT(KUsbSCLDDName, "eusbcsc");
+    err = User::LoadLogicalDevice(KUsbSCLDDName);
+    OstTrace1( TRACE_NORMAL, CNCMCLASSCONTROLLER_CONSTRUCTL_LOAD_CSC_LDD, "LoadLogicalDevice() returns %d!", err );
+    if (err != KErrNone && err != KErrAlreadyExists)
+        {
+        User::Leave(err);
+        }
+    OstTrace0(TRACE_NORMAL, CNCMCLASSCONTROLLER_CONSTRUCTL_CSC_LDD_LOADED, "Ldd eusbcsc loaded!");    
+#endif // OVERDUMMY_NCMCC
+    
+    RandomMacAddressL(); // Create a random MAC address for NCM host side interface.
+    iConnectionMan = CNcmConnectionManager::NewL(*this, iHostMacAddress, iDataBufferSize, iNcmInternalSvr);
+    iClientMgr = new  (ELeave) CNcmClientManager(iHostMacAddress);
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_CONSTRUCTL_EXIT, this );
+    }
+
+void CNcmClassController::RandomMacAddressL()
+    {
+    OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_RANDOMMACADDRESSL_ENTRY, this );
+    
+    //Create the NCM interface MAC address randomly 
+    iHostMacAddress.SetLength(KEthernetAddressLength);
+    TRandom::RandomL(iHostMacAddress);
+  
+    //Mark it a locally administered address
+    iHostMacAddress[0] = 0x02;
+    iHostMacAddress[1] = 0x00;
+    iHostMacAddress[2] = 0x00;
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_RANDOMMACADDRESSL_EXIT, this );
+    }
+
+/**
+ * Destructor.
+ */
+CNcmClassController::~CNcmClassController()
+    {
+    OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_ENTRY_DESTROY, this );
+    Cancel();
+
+    // Close internal server to release some resource
+    iNcmInternalSvr.Close();
+    delete iClientMgr;
+    delete iConnectionMan;
+
+#ifndef OVERDUMMY_NCMCC
+    OstTrace0(TRACE_NORMAL, CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_PRE_UNLOAD_CSC_LDD, "About to unload Usbcsc!");
+    _LIT(KUsbSCLDDName, "Usbcsc");
+    TInt err = User::FreeLogicalDevice(KUsbSCLDDName);
+    OstTrace1(TRACE_NORMAL, CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_UNLOAD_LDD_RESULT, "FreeLogicalDevice() returns %d!", err);
+#endif // OVERDUMMY_NCMCC
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_EXIT_DESTROY, this );
+    }
+
+/**
+ * Called by UsbMan to start this class.
+ * @param aStatus Will be completed with success or failure.
+ */
+void CNcmClassController::Start(TRequestStatus& aStatus)
+    {
+    OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_START_ENTRY, this );
+    OstTrace1(TRACE_NORMAL, CNCMCLASSCONTROLLER_START_PRINT_STATE, "iState=%d", iState);
+    
+    //Start() should only be called if the CC is idle state		
+    __ASSERT_DEBUG((iState == EUsbServiceIdle),
+            User::Panic(KNcmControllerPanic, ENcmPanicBadApiCallStart));
+
+    // NB We enforce that the device doesn't re-post requests on us.
+    __ASSERT_DEBUG(!iReportStatus,
+            User::Panic(KNcmControllerPanic, ENcmPanicOutstandingRequestFromDevice));
+
+    // We should not be active before start
+    __ASSERT_DEBUG(!IsActive(), User::Panic(KNcmControllerPanic, ENcmPanicAlreadyActive));
+
+    aStatus = KRequestPending;
+    iReportStatus = &aStatus;
+
+    iState = EUsbServiceStarting;
+
+    // According to the latest discussion of 100ms limitation to 
+    // each personality starting, the calling to iConnectionMan->Start
+    // will happen later. A controller will set sevice state to started
+    // immediately after calling to RDevUsbcScClient::SetInterface()
+
+    TInt err = KErrNone;
+    
+    // Can not leave. Trap any error from SetNcmInterfacesL()
+    TRAP(err, iClientMgr->SetNcmInterfacesL(iDataBufferSize));
+    User::RequestComplete(iReportStatus, err);
+    
+    if (KErrNone == err)
+        {
+        // Set service state to started
+        iState = EUsbServiceStarted;
+        
+        iStatus = KRequestPending;
+        SetActive();
+        TRequestStatus* status = &iStatus;
+        User::RequestComplete(status, err);
+        }
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_START_EXIT, this );
+    }
+
+/**
+ * Called by UsbMan to stop this class.
+ * @param aStatus Will be completed with success or failure.
+ */
+void CNcmClassController::Stop(TRequestStatus& aStatus)
+    {
+    OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_STOP_ENTRY, this );
+    OstTrace1( TRACE_NORMAL, CNCMCLASSCONTROLLER_STOP_PRINT_STATE, "iState=%d", iState );
+
+    __ASSERT_DEBUG(((iState == EUsbServiceStarted)||(iState == EUsbServiceStarting)),
+            User::Panic(KNcmControllerPanic, ENcmPanicBadApiCallStop));
+
+    // NB We enforce that the device doesn't re-post requests on us.
+    __ASSERT_DEBUG(!iReportStatus,
+            User::Panic(KNcmControllerPanic, ENcmPanicOutstandingRequestFromDevice));
+        
+    if (IsActive()) // Networking connetion building is ongoing!
+        {
+        Cancel();
+        }
+    else
+        {
+        iConnectionMan->Stop();
+        }
+
+    aStatus = KRequestPending;
+    iReportStatus = &aStatus;
+    User::RequestComplete(iReportStatus, KErrNone);
+    
+    iConnectingToNcmPktDrv = EFalse;
+    iState = EUsbServiceIdle;
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_STOP_EXIT, this );
+    }
+
+/**
+ * Returns information about the interfaces supported by this class.
+ * @param aDescriptorInfo Will be filled in with interface information.
+ */
+void CNcmClassController::GetDescriptorInfo(
+        TUsbDescriptor& aDescriptorInfo) const
+    {
+    OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_GETDESCRIPTORINFO_ENTRY, this );
+
+    aDescriptorInfo.iNumInterfaces = 2;
+    aDescriptorInfo.iLength = KNcmDescriptorLength;
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_GETDESCRIPTORINFO_EXIT, this );
+    }
+
+void CNcmClassController::McmoErrorIndication(TInt aError)
+    {
+    OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_MCMOERRORINDICATION_ENTRY, this );
+
+    Owner().UccnError(aError);
+    
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_MCMOERRORINDICATION_EXIT, this );
+    }
+
+/**
+ * Called when connection manager completes.
+ */
+void CNcmClassController::RunL()
+    {
+    OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_RUNL_ENTRY, this );
+    TInt completionCode = iStatus.Int();
+    OstTraceExt2( TRACE_NORMAL, CNCMCLASSCONTROLLER_RUNL_PRINT_INFO, "iState=%d; completionCode=%d", iState, completionCode );
+    
+    // Goto RunError() to handle any exception
+    User::LeaveIfError(completionCode);
+    
+    // We should only be in starting state when connection manager completes. Stopping is a synchronous call.
+    __ASSERT_DEBUG(EUsbServiceStarted == iState, User::Panic(KNcmControllerPanic, 
+            ENcmPanicBadState));
+
+    switch (iState)
+        {
+        case EUsbServiceStarted:
+            {            
+            OstTrace0( TRACE_NORMAL, CNCMCLASSCONTROLLER_RUNL_STARTED, "EUsbServiceStarted" );
+            if (iConnectingToNcmPktDrv)
+                {
+                OstTrace0( TRACE_FLOW, CNCMCLASSCONTROLLER_RUNL_TRANSFER_HANDLES, "An Ethernet connection over NCM built. Transfer interface handlers to NCM internal server." );
+                // NCM Packet Driver Loaded in C32, now transfer LDD handles to packet driver side through NCM internal server
+                iClientMgr->TransferInterfacesL(iNcmInternalSvr);
+                            
+                delete iClientMgr;
+                iClientMgr = NULL;
+                }
+            else
+                {
+                OstTrace0( TRACE_NORMAL, CNCMCLASSCONTROLLER_RUNL_BUILT_NCM_CONNECTION, "Going to build ethernet connection over NCM!" );
+                iConnectingToNcmPktDrv = ETrue;
+                iStatus = KRequestPending;
+                SetActive();
+                iConnectionMan->Start(iStatus);
+                }
+            
+            break;
+            }
+            
+        default:
+            {
+            OstTrace0( TRACE_ERROR, CNCMCLASSCONTROLLER_RUNL_DEFAULT, "Default::SHOULD NOT BE HERE!!!" );
+            User::Panic(KNcmControllerPanic, ENcmPanicBadState);
+            break;
+            }
+        }
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_RUNL_EXIT, this );
+    }
+
+/**
+ * Implements cancellation of an outstanding request.
+ */
+void CNcmClassController::DoCancel()
+    {
+    OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_DOCANCEL_ENTRY, this );
+
+    OstTraceExt2( TRACE_NORMAL, CNCMCLASSCONTROLLER_DOCANCEL_INFO_PRINT, "iState=%d; iReportStatus=%p", iState, iReportStatus );
+
+    // Update our iState. If we're starting, then roll back to idle. If we're 
+    // stopping, role back to started. Nothing else is legal.
+    switch (iState)
+        {
+        case EUsbServiceStarted:
+            OstTrace0( TRACE_NORMAL, CNCMCLASSCONTROLLER_DOCANCEL_IDLE, "EUsbServiceIdle" );
+            iState = EUsbServiceIdle;
+            if (iConnectingToNcmPktDrv)
+                {
+                iConnectionMan->StartCancel();
+                }
+            __ASSERT_DEBUG(!iReportStatus, User::Panic(KNcmControllerPanic, ENcmPanicUnhandledError));
+            
+            OstTraceFunctionExit1( CNCMCLASSCONTROLLER_DOCANCEL_EXIT, this );
+            return;
+            
+        default:
+            OstTrace1(TRACE_FATAL, CNCMCLASSCONTROLLER_DOCANCEL_DEFAULT, "Default::Should not be here:iState=%d", iState);
+            User::Panic(KNcmControllerPanic, ENcmPanicBadState);
+            break;
+        }
+
+    // Complete the client's request.	
+    __ASSERT_DEBUG(iReportStatus, User::Panic(KNcmControllerPanic, ENcmPanicUnhandledError));
+    User::RequestComplete(iReportStatus, KErrCancel);
+
+    OstTraceFunctionExit1( CNCMCLASSCONTROLLER_DOCANCEL_EXIT_DUP1, this );
+    }
+
+/**
+ * Called when RunL leaves. Does nothing, just return KErrNone.
+ * @return Error code. Simply return KErrNone.
+ */
+TInt CNcmClassController::RunError(TInt aError)
+    {
+    OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_RUNERROR_ENTRY, this );
+    
+    if (KErrCancel != aError)
+        {
+        // Report this failure to the observer
+        // Finally this will report to usbman and NCM class will be stopped.    
+        McmoErrorIndication(aError);
+        }
+
+    OstTraceFunctionExitExt( CNCMCLASSCONTROLLER_RUNERROR_EXIT, this, KErrNone );
+    return KErrNone;
+    }