usbmgmt/usbmgr/device/classdrivers/ncm/classcontroller/src/ncmclasscontroller.cpp
branchRCL_3
changeset 15 f92a4f87e424
equal deleted inserted replaced
14:d3e8e7d462dd 15:f92a4f87e424
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 /**
       
    19  * @file
       
    20  * @internalComponent
       
    21  */
       
    22 
       
    23 #include <usb_std.h>
       
    24 #include <barsc.h>
       
    25 #include <barsread.h>
       
    26 #include <cusbclasscontrollerbase.h> 
       
    27 #include <musbclasscontrollernotify.h>
       
    28 #include <usb/usbncm.h>
       
    29 #include <random.h>
       
    30 
       
    31 #include "ncmclasscontroller.h"
       
    32 #include "ncmconnectionmanager.h"
       
    33 #include "ncmclientmanager.h"
       
    34 
       
    35 // For OST tracing
       
    36 #include "OstTraceDefinitions.h"
       
    37 #ifdef OST_TRACE_COMPILER_IN_USE
       
    38 #include "ncmclasscontrollerTraces.h"
       
    39 #endif
       
    40 
       
    41 
       
    42 using namespace UsbNcm;
       
    43 _LIT(KNcmControllerPanic, "UsbNcmCC"); // must be <=16 chars
       
    44 const TInt KNcmStartupPriority = 3;
       
    45 
       
    46 // MTU size. 
       
    47 extern const TUint KEthernetFrameSize = 8192;
       
    48 
       
    49 // Lengths of the various bits of the NCM descriptor. Taken from the NCM Specification rev 1.0.
       
    50 const TInt KNcmInterfaceDescriptorLength = 3;
       
    51 const TInt KNcmCcHeaderDescriptorLength = 5;
       
    52 const TInt KNcmFunctionalDescriptorLength = 4;
       
    53 const TInt KNcmCcUfdDescriptorLength = 5;
       
    54 const TInt KNcmDataClassHeaderDescriptorLength = 5;
       
    55 const TInt KNcmDeviceDescriptorLength = 18;
       
    56 const TInt KNcmConfigurationDescriptorLength = 9;
       
    57 const TInt KNcmCommunicationClassEndpointOutDescriptorLength = 9;
       
    58 const TInt KNcmNotificationEndpointDescriptorLength = 7;
       
    59 const TInt KNcmDataClassInterfaceDescriptorLength = 9;
       
    60 const TInt KNcmDataClassEndpointInDescriptorLength = 7;
       
    61 const TInt KNcmDataClassEndpointOutDescriptorLength = 7;
       
    62 
       
    63 const TInt KNcmDescriptorLength = KNcmInterfaceDescriptorLength
       
    64         + KNcmCcHeaderDescriptorLength + KNcmFunctionalDescriptorLength
       
    65         + KNcmCcUfdDescriptorLength + KNcmDataClassHeaderDescriptorLength
       
    66         + KNcmDeviceDescriptorLength + KNcmConfigurationDescriptorLength
       
    67         + KNcmCommunicationClassEndpointOutDescriptorLength
       
    68         + KNcmNotificationEndpointDescriptorLength
       
    69         + KNcmDataClassInterfaceDescriptorLength
       
    70         + KNcmDataClassEndpointInDescriptorLength
       
    71         + KNcmDataClassEndpointOutDescriptorLength;
       
    72 
       
    73 // Panic codes
       
    74 enum TNcmClassControllerPanicCode
       
    75     {
       
    76     ENcmPanicBadState = 1,
       
    77     ENcmPanicOutstandingRequestFromDevice,
       
    78     ENcmPanicAlreadyActive,
       
    79     ENcmPanicUnhandledError,
       
    80     ENcmPanicBadApiCallStart, // Attempt to call Start() when in illegal state
       
    81     ENcmPanicBadApiCallStop, // Attempt to call Stop() when in illegal state
       
    82     ENcmPanicUnexpectedIapState,
       
    83     ENcmPanicUnexpectedError
       
    84     };
       
    85 
       
    86 /**
       
    87  * Constructs a CNcmClassController object.
       
    88  * @param aOwner USB Device that owns and manages the class
       
    89  * @return Ownership of a new CNcmClassController object
       
    90  */
       
    91 CNcmClassController* CNcmClassController::NewL(
       
    92         MUsbClassControllerNotify & aOwner)
       
    93     {
       
    94     OstTraceFunctionEntry0( CNCMCLASSCONTROLLER_NEWL_ENTRY );
       
    95 
       
    96     CNcmClassController* self =
       
    97             new (ELeave) CNcmClassController(aOwner);
       
    98     CleanupStack::PushL(self);
       
    99     self->ConstructL();
       
   100     CleanupStack::Pop(self);
       
   101     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_NEWL_EXIT, ( TUint )( self ) );
       
   102     return self;
       
   103     }
       
   104 
       
   105 /**
       
   106  * Constructor.
       
   107  * @param aOwner USB Device that owns and manages the class
       
   108  */
       
   109 CNcmClassController::CNcmClassController(
       
   110         MUsbClassControllerNotify& aOwner) :
       
   111     CUsbClassControllerPlugIn(aOwner, KNcmStartupPriority)
       
   112     {
       
   113     OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_ENTRY, this );
       
   114     
       
   115     iState = EUsbServiceIdle; // needs explicit initialisation as non-zero
       
   116     
       
   117     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_EXIT, this );
       
   118     }
       
   119 
       
   120 /**
       
   121  * Method to perform second phase construction.
       
   122  */
       
   123 void CNcmClassController::ConstructL()
       
   124     {
       
   125     OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_CONSTRUCTL_ENTRY, this );
       
   126     
       
   127 #ifndef OVERDUMMY_NCMCC
       
   128     TInt err = KErrNone;
       
   129     
       
   130     OstTrace0(TRACE_NORMAL, CNCMCLASSCONTROLLER_CONSTRUCTL, "About to load eusbcsc!");
       
   131     _LIT(KUsbSCLDDName, "eusbcsc");
       
   132     err = User::LoadLogicalDevice(KUsbSCLDDName);
       
   133     OstTrace1( TRACE_NORMAL, CNCMCLASSCONTROLLER_CONSTRUCTL_LOAD_CSC_LDD, "LoadLogicalDevice() returns %d!", err );
       
   134     if (err != KErrNone && err != KErrAlreadyExists)
       
   135         {
       
   136         User::Leave(err);
       
   137         }
       
   138     OstTrace0(TRACE_NORMAL, CNCMCLASSCONTROLLER_CONSTRUCTL_CSC_LDD_LOADED, "Ldd eusbcsc loaded!");    
       
   139 #endif // OVERDUMMY_NCMCC
       
   140     
       
   141     RandomMacAddressL(); // Create a random MAC address for NCM host side interface.
       
   142     iConnectionMan = CNcmConnectionManager::NewL(*this, iHostMacAddress, iDataBufferSize, iNcmInternalSvr);
       
   143     iClientMgr = new  (ELeave) CNcmClientManager(iHostMacAddress);
       
   144     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_CONSTRUCTL_EXIT, this );
       
   145     }
       
   146 
       
   147 void CNcmClassController::RandomMacAddressL()
       
   148     {
       
   149     OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_RANDOMMACADDRESSL_ENTRY, this );
       
   150     
       
   151     //Create the NCM interface MAC address randomly 
       
   152     iHostMacAddress.SetLength(KEthernetAddressLength);
       
   153     TRandom::RandomL(iHostMacAddress);
       
   154   
       
   155     //Mark it a locally administered address
       
   156     iHostMacAddress[0] = 0x02;
       
   157     iHostMacAddress[1] = 0x00;
       
   158     iHostMacAddress[2] = 0x00;
       
   159     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_RANDOMMACADDRESSL_EXIT, this );
       
   160     }
       
   161 
       
   162 /**
       
   163  * Destructor.
       
   164  */
       
   165 CNcmClassController::~CNcmClassController()
       
   166     {
       
   167     OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_ENTRY_DESTROY, this );
       
   168     Cancel();
       
   169 
       
   170     // Close internal server to release some resource
       
   171     iNcmInternalSvr.Close();
       
   172     delete iClientMgr;
       
   173     delete iConnectionMan;
       
   174 
       
   175 #ifndef OVERDUMMY_NCMCC
       
   176     OstTrace0(TRACE_NORMAL, CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_PRE_UNLOAD_CSC_LDD, "About to unload Usbcsc!");
       
   177     _LIT(KUsbSCLDDName, "Usbcsc");
       
   178     TInt err = User::FreeLogicalDevice(KUsbSCLDDName);
       
   179     OstTrace1(TRACE_NORMAL, CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_UNLOAD_LDD_RESULT, "FreeLogicalDevice() returns %d!", err);
       
   180 #endif // OVERDUMMY_NCMCC
       
   181     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_CNCMCLASSCONTROLLER_EXIT_DESTROY, this );
       
   182     }
       
   183 
       
   184 /**
       
   185  * Called by UsbMan to start this class.
       
   186  * @param aStatus Will be completed with success or failure.
       
   187  */
       
   188 void CNcmClassController::Start(TRequestStatus& aStatus)
       
   189     {
       
   190     OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_START_ENTRY, this );
       
   191     OstTrace1(TRACE_NORMAL, CNCMCLASSCONTROLLER_START_PRINT_STATE, "iState=%d", iState);
       
   192     
       
   193     //Start() should only be called if the CC is idle state		
       
   194     __ASSERT_DEBUG((iState == EUsbServiceIdle),
       
   195             User::Panic(KNcmControllerPanic, ENcmPanicBadApiCallStart));
       
   196 
       
   197     // NB We enforce that the device doesn't re-post requests on us.
       
   198     __ASSERT_DEBUG(!iReportStatus,
       
   199             User::Panic(KNcmControllerPanic, ENcmPanicOutstandingRequestFromDevice));
       
   200 
       
   201     // We should not be active before start
       
   202     __ASSERT_DEBUG(!IsActive(), User::Panic(KNcmControllerPanic, ENcmPanicAlreadyActive));
       
   203 
       
   204     aStatus = KRequestPending;
       
   205     iReportStatus = &aStatus;
       
   206 
       
   207     iState = EUsbServiceStarting;
       
   208 
       
   209     // According to the latest discussion of 100ms limitation to 
       
   210     // each personality starting, the calling to iConnectionMan->Start
       
   211     // will happen later. A controller will set sevice state to started
       
   212     // immediately after calling to RDevUsbcScClient::SetInterface()
       
   213 
       
   214     TInt err = KErrNone;
       
   215     
       
   216     // Can not leave. Trap any error from SetNcmInterfacesL()
       
   217     TRAP(err, iClientMgr->SetNcmInterfacesL(iDataBufferSize));
       
   218     User::RequestComplete(iReportStatus, err);
       
   219     
       
   220     if (KErrNone == err)
       
   221         {
       
   222         // Set service state to started
       
   223         iState = EUsbServiceStarted;
       
   224         
       
   225         iStatus = KRequestPending;
       
   226         SetActive();
       
   227         TRequestStatus* status = &iStatus;
       
   228         User::RequestComplete(status, err);
       
   229         }
       
   230     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_START_EXIT, this );
       
   231     }
       
   232 
       
   233 /**
       
   234  * Called by UsbMan to stop this class.
       
   235  * @param aStatus Will be completed with success or failure.
       
   236  */
       
   237 void CNcmClassController::Stop(TRequestStatus& aStatus)
       
   238     {
       
   239     OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_STOP_ENTRY, this );
       
   240     OstTrace1( TRACE_NORMAL, CNCMCLASSCONTROLLER_STOP_PRINT_STATE, "iState=%d", iState );
       
   241 
       
   242     __ASSERT_DEBUG(((iState == EUsbServiceStarted)||(iState == EUsbServiceStarting)),
       
   243             User::Panic(KNcmControllerPanic, ENcmPanicBadApiCallStop));
       
   244 
       
   245     // NB We enforce that the device doesn't re-post requests on us.
       
   246     __ASSERT_DEBUG(!iReportStatus,
       
   247             User::Panic(KNcmControllerPanic, ENcmPanicOutstandingRequestFromDevice));
       
   248         
       
   249     if (IsActive()) // Networking connetion building is ongoing!
       
   250         {
       
   251         Cancel();
       
   252         }
       
   253     else
       
   254         {
       
   255         iConnectionMan->Stop();
       
   256         }
       
   257 
       
   258     aStatus = KRequestPending;
       
   259     iReportStatus = &aStatus;
       
   260     User::RequestComplete(iReportStatus, KErrNone);
       
   261     
       
   262     iConnectingToNcmPktDrv = EFalse;
       
   263     iState = EUsbServiceIdle;
       
   264     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_STOP_EXIT, this );
       
   265     }
       
   266 
       
   267 /**
       
   268  * Returns information about the interfaces supported by this class.
       
   269  * @param aDescriptorInfo Will be filled in with interface information.
       
   270  */
       
   271 void CNcmClassController::GetDescriptorInfo(
       
   272         TUsbDescriptor& aDescriptorInfo) const
       
   273     {
       
   274     OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_GETDESCRIPTORINFO_ENTRY, this );
       
   275 
       
   276     aDescriptorInfo.iNumInterfaces = 2;
       
   277     aDescriptorInfo.iLength = KNcmDescriptorLength;
       
   278     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_GETDESCRIPTORINFO_EXIT, this );
       
   279     }
       
   280 
       
   281 void CNcmClassController::McmoErrorIndication(TInt aError)
       
   282     {
       
   283     OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_MCMOERRORINDICATION_ENTRY, this );
       
   284 
       
   285     Owner().UccnError(aError);
       
   286     
       
   287     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_MCMOERRORINDICATION_EXIT, this );
       
   288     }
       
   289 
       
   290 /**
       
   291  * Called when connection manager completes.
       
   292  */
       
   293 void CNcmClassController::RunL()
       
   294     {
       
   295     OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_RUNL_ENTRY, this );
       
   296     TInt completionCode = iStatus.Int();
       
   297     OstTraceExt2( TRACE_NORMAL, CNCMCLASSCONTROLLER_RUNL_PRINT_INFO, "iState=%d; completionCode=%d", iState, completionCode );
       
   298     
       
   299     // Goto RunError() to handle any exception
       
   300     User::LeaveIfError(completionCode);
       
   301     
       
   302     // We should only be in starting state when connection manager completes. Stopping is a synchronous call.
       
   303     __ASSERT_DEBUG(EUsbServiceStarted == iState, User::Panic(KNcmControllerPanic, 
       
   304             ENcmPanicBadState));
       
   305 
       
   306     switch (iState)
       
   307         {
       
   308         case EUsbServiceStarted:
       
   309             {            
       
   310             OstTrace0( TRACE_NORMAL, CNCMCLASSCONTROLLER_RUNL_STARTED, "EUsbServiceStarted" );
       
   311             if (iConnectingToNcmPktDrv)
       
   312                 {
       
   313                 OstTrace0( TRACE_FLOW, CNCMCLASSCONTROLLER_RUNL_TRANSFER_HANDLES, "An Ethernet connection over NCM built. Transfer interface handlers to NCM internal server." );
       
   314                 // NCM Packet Driver Loaded in C32, now transfer LDD handles to packet driver side through NCM internal server
       
   315                 iClientMgr->TransferInterfacesL(iNcmInternalSvr);
       
   316                             
       
   317                 delete iClientMgr;
       
   318                 iClientMgr = NULL;
       
   319                 }
       
   320             else
       
   321                 {
       
   322                 OstTrace0( TRACE_NORMAL, CNCMCLASSCONTROLLER_RUNL_BUILT_NCM_CONNECTION, "Going to build ethernet connection over NCM!" );
       
   323                 iConnectingToNcmPktDrv = ETrue;
       
   324                 iStatus = KRequestPending;
       
   325                 SetActive();
       
   326                 iConnectionMan->Start(iStatus);
       
   327                 }
       
   328             
       
   329             break;
       
   330             }
       
   331             
       
   332         default:
       
   333             {
       
   334             OstTrace0( TRACE_ERROR, CNCMCLASSCONTROLLER_RUNL_DEFAULT, "Default::SHOULD NOT BE HERE!!!" );
       
   335             User::Panic(KNcmControllerPanic, ENcmPanicBadState);
       
   336             break;
       
   337             }
       
   338         }
       
   339     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_RUNL_EXIT, this );
       
   340     }
       
   341 
       
   342 /**
       
   343  * Implements cancellation of an outstanding request.
       
   344  */
       
   345 void CNcmClassController::DoCancel()
       
   346     {
       
   347     OstTraceFunctionEntry1( CNCMCLASSCONTROLLER_DOCANCEL_ENTRY, this );
       
   348 
       
   349     OstTraceExt2( TRACE_NORMAL, CNCMCLASSCONTROLLER_DOCANCEL_INFO_PRINT, "iState=%d; iReportStatus=%p", iState, iReportStatus );
       
   350 
       
   351     // Update our iState. If we're starting, then roll back to idle. If we're 
       
   352     // stopping, role back to started. Nothing else is legal.
       
   353     switch (iState)
       
   354         {
       
   355         case EUsbServiceStarted:
       
   356             OstTrace0( TRACE_NORMAL, CNCMCLASSCONTROLLER_DOCANCEL_IDLE, "EUsbServiceIdle" );
       
   357             iState = EUsbServiceIdle;
       
   358             if (iConnectingToNcmPktDrv)
       
   359                 {
       
   360                 iConnectionMan->StartCancel();
       
   361                 }
       
   362             __ASSERT_DEBUG(!iReportStatus, User::Panic(KNcmControllerPanic, ENcmPanicUnhandledError));
       
   363             
       
   364             OstTraceFunctionExit1( CNCMCLASSCONTROLLER_DOCANCEL_EXIT, this );
       
   365             return;
       
   366             
       
   367         default:
       
   368             OstTrace1(TRACE_FATAL, CNCMCLASSCONTROLLER_DOCANCEL_DEFAULT, "Default::Should not be here:iState=%d", iState);
       
   369             User::Panic(KNcmControllerPanic, ENcmPanicBadState);
       
   370             break;
       
   371         }
       
   372 
       
   373     // Complete the client's request.	
       
   374     __ASSERT_DEBUG(iReportStatus, User::Panic(KNcmControllerPanic, ENcmPanicUnhandledError));
       
   375     User::RequestComplete(iReportStatus, KErrCancel);
       
   376 
       
   377     OstTraceFunctionExit1( CNCMCLASSCONTROLLER_DOCANCEL_EXIT_DUP1, this );
       
   378     }
       
   379 
       
   380 /**
       
   381  * Called when RunL leaves. Does nothing, just return KErrNone.
       
   382  * @return Error code. Simply return KErrNone.
       
   383  */
       
   384 TInt CNcmClassController::RunError(TInt aError)
       
   385     {
       
   386     OstTraceFunctionEntryExt( CNCMCLASSCONTROLLER_RUNERROR_ENTRY, this );
       
   387     
       
   388     if (KErrCancel != aError)
       
   389         {
       
   390         // Report this failure to the observer
       
   391         // Finally this will report to usbman and NCM class will be stopped.    
       
   392         McmoErrorIndication(aError);
       
   393         }
       
   394 
       
   395     OstTraceFunctionExitExt( CNCMCLASSCONTROLLER_RUNERROR_EXIT, this, KErrNone );
       
   396     return KErrNone;
       
   397     }