usbengines/usbdevcon/src/cusbdevcon.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:14:30 +0200
changeset 0 1e05558e2206
child 15 5325df355191
child 21 ff9df6630274
child 26 0ae0f29418cd
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2007 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:  Takes control of device&vendor-specific control messages over EP0
*
*/


#include <usbman.h>

#include "cusbdevcon.h"
#include "cusbstatewatcher.h"
#include "crequestshandler.h"
#include "cstatemachine.h"
#include "debug.h"

// LITERALS
_LIT( KUsbDevConName, "UsbDevCon" );

// ---------------------------------------------------------------------------
// Two-phase construction
// ---------------------------------------------------------------------------
//
CUsbDevCon* CUsbDevCon::NewLC()
    {
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::NewLC" ) );
    
    CUsbDevCon* self = new (ELeave) CUsbDevCon();
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// ---------------------------------------------------------------------------
// Two-phase construction
// ---------------------------------------------------------------------------
//  
CUsbDevCon* CUsbDevCon::NewL()
    {
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::NewL" ) );
    
    CUsbDevCon* self = CUsbDevCon::NewLC();
    CleanupStack::Pop(self);
    return self;    
    }

// ---------------------------------------------------------------------------
// Two-phase construction
// ---------------------------------------------------------------------------
//  
void CUsbDevCon::ConstructL()
    {
    
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ConstructL" ) );
    
    // usbc
    User::LeaveIfError(iLdd.Open(0));
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ConstructL RDevUsbcClient opened OK" ) );
    
    // usb manager
    User::LeaveIfError(iUsbManager.Connect());
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ConstructL RUsb connected OK" ) );
    
    // usb watcher
    User::LeaveIfError(iUsbWatcher.Connect());
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ConstructL RUsbWatcher connected OK" ) );
    
    // device state watcher
    iUsbStateWatcher = CUsbStateWatcher::NewL(*this, iLdd);
        
    // Requests handler
    iRequestsHandler = CRequestsHandler::NewL(iLdd, iUsbWatcher, iUsbManager);
    
    // state machine
    iStateMachine = CStateMachine::NewL(*iRequestsHandler, iLdd);
    
     User::LeaveIfError(iShutdownTimer.CreateLocal());
    
    // get usb state, and act accordingly to it
    TUsbcDeviceState usbcstate(EUsbcDeviceStateUndefined);
    iLdd.DeviceStatus(usbcstate);
    
    FTRACE(FPrint(
            _L("[USBDEVCON]\tCUsbDevCon::ConstructL: Usbc state = %d" ),usbcstate));
    
    ActAccordinglyToUsbStateL(usbcstate);
     
    }

// ---------------------------------------------------------------------------
// Default construction
// ---------------------------------------------------------------------------
//  
CUsbDevCon::CUsbDevCon() : CActive(EPriorityStandard),
                             iUsbStateWatcher(0),
                             iStateMachine (0),
                             iRequestsHandler(0),
                             iPrevUsbState(EUsbcDeviceStateUndefined)
    {
    CActiveScheduler::Add(this);
     }

// ---------------------------------------------------------------------------
// Destruction
// ---------------------------------------------------------------------------
//
CUsbDevCon::~CUsbDevCon()
    {
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon" ) );
        
        Cancel();
        
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon Cancel" ) );
        
        delete iStateMachine;
        
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon StateMachine" ) );
        
        delete iRequestsHandler;
        
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon RequestsHandler" ) );
        
        delete iUsbStateWatcher;
        
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon UsbStateWatcher" ) );
        
        iUsbWatcher.Close();
        
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon UsbWatcher" ) );
        
        iUsbManager.Close();
        
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon UsbManager" ) );
        
        iLdd.Close();
        
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon LDD" ) );
        
        iShutdownTimer.Close();
        
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::~CUsbDevCon Timer" ) );
    
    }   

// ---------------------------------------------------------------------------
// Acts accordingly to USB state
// ---------------------------------------------------------------------------
//
void CUsbDevCon::ActAccordinglyToUsbStateL(TUsbcDeviceState aUsbcState)
    {
    
    switch (aUsbcState)
        {
        case EUsbcDeviceStateUndefined:
            {
            
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ActAccordinglyToUsbStateL State: Undefined" ) );
                    
            StopL();
            break;
            }
                
        case EUsbcDeviceStateAttached:
            {
            
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ActAccordinglyToUsbStateL State: Attached" ) );     

            StartL();
            break;
            }
                
        case EUsbcDeviceStatePowered:
            {
            
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ActAccordinglyToUsbStateL State: Powered" ) );      

            StartL();
            break;
            }
                
        case EUsbcDeviceStateDefault:
            {
                
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ActAccordinglyToUsbStateL State: Default" ) );      

            StartL();
            break;
            }
                
        case EUsbcDeviceStateAddress:
            {
                
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ActAccordinglyToUsbStateL State: Addressed" ) );        

            StartL();
            break;
            }
                
        case EUsbcDeviceStateConfigured:
            {
                
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ActAccordinglyToUsbStateL State: Configured" ) );       

            if(iPrevUsbState == EUsbcDeviceStateSuspended)
                {
                ResumeL();
                }
                else
                {
                StartL();
                }
                
            break;
            }
        case EUsbcDeviceStateSuspended:
            {
                
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ActAccordinglyToUsbStateL State: Suspended" ) );        

            break;
            }
                
        default:
            {
                
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ActAccordinglyToUsbStateL State: ***Undefined***" ) );      

            StopL();
            break;
            }
        }
            
    iPrevUsbState = aUsbcState;
            
    // listen to USB states change
    iUsbStateWatcher->Activate();
    
    }
    
 // ---------------------------------------------------------------------------
// Timer is completed
// ---------------------------------------------------------------------------
//   
void CUsbDevCon::RunL()
    {
    FTRACE(FPrint(
            _L("[USBDEVCON]\tCUsbDevCon::RunL: iStatus = %d" ),iStatus.Int()));
   
    if(KErrNone == iStatus.Int())
        {
        FLOG( _L( "[USBDEVCON]\tCUsbDevCon::RunL Exiting usbdevcon" ) );      
        
        // Shutdown timer is finished, exit program
        CUsbDevCon:: ~CUsbDevCon(); // destruct resources
        User::Exit(KErrNone);
        }
    }

// ---------------------------------------------------------------------------
// Cancellation
// ---------------------------------------------------------------------------
//   
void CUsbDevCon::DoCancel()
    {
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::DoCancel" ) )
    iShutdownTimer.Cancel();      
    }
    
// ----------------------------------------------------------------------------
// Standard active object error function.
// ----------------------------------------------------------------------------
//
TInt CUsbDevCon::RunError( TInt /*aError*/ )
    {
    return KErrNone;
    }
    
// ---------------------------------------------------------------------------
// Starts UsbDevCon services
// ---------------------------------------------------------------------------
//
void CUsbDevCon::StartL()
    {
    
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::StartL" ) );        

    if(!iStateMachine->IsStarted())
        {
        // set device control
        User::LeaveIfError(iLdd.SetDeviceControl());
        
        // start state machine
        iStateMachine->Start();
        
        }
        
        // Cancel shutdown timer, if it is started
        iShutdownTimer.Cancel();
     }
    
// ---------------------------------------------------------------------------
// Stops UsbDevCon services
// ---------------------------------------------------------------------------
//
void CUsbDevCon::StopL()
    {
    
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::StopL" ) );
    
    if(iStateMachine->IsStarted())
        {
        
        // stop state machine
        iStateMachine->Stop();
        
        // release device control
        User::LeaveIfError(iLdd.ReleaseDeviceControl());
        
         }
         
         if(!IsActive()) // not waiting for timer
            {
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::StopL Starting timer" ) );
            // run timer
            iShutdownTimer.Cancel();

            // RunL will be called after KInactiveTimeForShutDown milliseconds
            iShutdownTimer.After(iStatus, TTimeIntervalMicroSeconds32(KInactiveTimeForShutDown)); 
            SetActive();
            FLOG( _L( "[USBDEVCON]\tCUsbDevCon::StopL Timer is started" ) );
            }
    }
    
// ---------------------------------------------------------------------------
// Resumes UsbDevCon services 
// ---------------------------------------------------------------------------
//
void CUsbDevCon::ResumeL()
    {
    
    FLOG( _L( "[USBDEVCON]\tCUsbDevCon::ResumeL" ) );
    
    // Resume state machine
    StartL();
    
    }

// ----------------------------------------------------------------------------
// Constructs and installs the active scheduler, constructs UsbDevCon object.
// ----------------------------------------------------------------------------
//
static void StartUsbDevConL()
    {
    
    FLOG( _L( "[USBDEVCON]\tStartUsbDevConL" ) );
        
    // Construct and install the active scheduler
    CActiveScheduler *myScheduler = new ( ELeave ) CActiveScheduler();

    // Push onto the cleanup stack
    CleanupStack::PushL( myScheduler );

    // Install as the active scheduler
    CActiveScheduler::Install( myScheduler );
    
    CUsbDevCon* instance =  CUsbDevCon::NewLC();
    
    RProcess::Rendezvous(KErrNone); // signal to starter process, that usbdevcon started OK or failed to start
           
    FLOG( _L( "[USBDEVCON]\tStartUsbDevConL Usbdevcon is started successfully" ) );
    
    // returns only when UsbDevCon closing
    CActiveScheduler::Start();

    CleanupStack::PopAndDestroy( instance );
    CleanupStack::PopAndDestroy( myScheduler );
    }

// ---------------------------------------------------------------------------
// Main function of the application executable.
// ---------------------------------------------------------------------------
//
GLDEF_C TInt E32Main()
    {
    TInt err;
    
    // rename the thread so it is easy to find the panic application
    err = User::RenameThread(KUsbDevConName);
    
    if(KErrNone != err)
        {
        return err;
        }
    
    __UHEAP_MARK;
    
    // create clean-up stack
    CTrapCleanup* cleanup = CTrapCleanup::New();
    
    TRAP( err, StartUsbDevConL() );
    
    delete cleanup; // destroy clean-up stack
    __UHEAP_MARKEND;

    return err;
    }