localconnectivityservice/generichid/src/hidgeneric.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:03:15 +0300
branchRCL_3
changeset 19 0aa8cc770c8a
permissions -rw-r--r--
Revision: 201032 Kit: 201035

/*
* Copyright (c) 2004-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:  Generic hid implementation
*
*/

#include <e32std.h>

#include "debug.h"
#include "hidgeneric.h"
#include "hidreportroot.h"
#include "hidparser.h"
#include "hiddriveritem.h"
#include "hidconnectioninfo.h"

// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// NewLC
// ---------------------------------------------------------------------------
//
EXPORT_C CGenericHid* CGenericHid::NewLC(MTransportLayer* aTransportLayer)
    {
    TRACE_INFO((_L("[HID]\tCGenericHid::NewLC(0x%08x)"), aTransportLayer));
    CGenericHid* self = new (ELeave) CGenericHid(aTransportLayer);
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// ---------------------------------------------------------------------------
// NewL
// ---------------------------------------------------------------------------
//
EXPORT_C CGenericHid* CGenericHid::NewL(MTransportLayer* aTransportLayer)
    {
    TRACE_INFO((_L("[HID]\tCGenericHid::NewL(0x%08x)"), aTransportLayer));
	CGenericHid* self = NewLC(aTransportLayer);
    CleanupStack::Pop();
    return self;
    }

// ---------------------------------------------------------------------------
// ConstructL()
// ---------------------------------------------------------------------------
//
void CGenericHid::ConstructL()
    {
    TRACE_INFO(_L("[HID]\tCGenericHid::ConstructL()"));
    TRACE_INFO(_L("[HID]\tCGenericHid::ConstructL(): Creating Parser..."));
    iParser = CParser::NewL();
    iInputHandlingReg = CHidInputDataHandlingReg::NewL();
    }

// ---------------------------------------------------------------------------
// CGenericHid()
// ---------------------------------------------------------------------------
//
CGenericHid::CGenericHid(MTransportLayer* aTransportLayer) :
    iDriverList(_FOFF(CDriverListItem, iSlink)),
    iTransportLayer(aTransportLayer)
    {
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CGenericHid::~CGenericHid()
    {
    TRACE_FUNC_ENTRY
    RemoveDrivers();
    iConnectionInfo.ResetAndDestroy();
    iConnectionInfo.Close();
    delete iInputHandlingReg;
    delete iParser;
    REComSession::FinalClose();
    TRACE_FUNC_EXIT
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// CountryCodeL
// ---------------------------------------------------------------------------
//
TUint CGenericHid::CountryCodeL(TInt aConnID)
    {
    // Pass the request through to the transport layer.
    return (iTransportLayer->CountryCodeL(aConnID));
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// VendorIdL
// ---------------------------------------------------------------------------
//
TUint CGenericHid::VendorIdL(TInt aConnID)
    {
    // Pass the request through to the transport layer.
    return (iTransportLayer->VendorIdL(aConnID));
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// ProductIdL()
// ---------------------------------------------------------------------------
//
TUint CGenericHid::ProductIdL(TInt aConnID)
    {
    // Pass the request through to the transport layer.
    return iTransportLayer->ProductIdL(aConnID);
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// SetProtocol
// ---------------------------------------------------------------------------
//
void CGenericHid::SetProtocolL(TInt aConnectionId, TUint16 aInterface,
                              MDriverAccess::TProtocols aProtocol, 
                              CHidDriver* aDriver)
    {
    iTransportLayer->SetProtocolL(aConnectionId, static_cast<TUint16>(aProtocol), 
            aInterface);    
    CConnectionInfo* conninfo = SeekConnectionInfo( aConnectionId );
        if ( conninfo )
            {
            conninfo->SetLastCommandHandler(aDriver);
            }          
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// GetProtocol
// ---------------------------------------------------------------------------
//
void CGenericHid::GetProtocolL(TInt aConnectionId,TUint16 aInterface)
    {
    iTransportLayer->GetProtocolL(aConnectionId, aInterface);    
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// GetReport
// ---------------------------------------------------------------------------
//
void CGenericHid::GetReportL(TInt aConnectionId,
    TUint8 aReportId, TUint16 aInterface, TUint16 aLength)
    {
    iTransportLayer->GetReportL(aConnectionId, MDriverAccess::EInput, aReportId, 
            aInterface, aLength);    
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// SetReport()
// ---------------------------------------------------------------------------
//
void CGenericHid::SetReportL(TInt aConnectionId, TUint8 aReportId,
    MDriverAccess::TReportType aReportType, const TDesC8& aPayload,
    TUint16 aInterface, CHidDriver* aDriver)
    {
    iTransportLayer->SetReportL(aConnectionId, static_cast<TUint8>(aReportType),
        aReportId, aInterface, aPayload);    
    CConnectionInfo* conninfo = SeekConnectionInfo( aConnectionId );
        if ( conninfo )
            {
            conninfo->SetLastCommandHandler(aDriver);
            }          
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// DataOut()
// ---------------------------------------------------------------------------
//
void CGenericHid::DataOutL(TInt aConnectionId, TUint8 aReportId,
                          const TDesC8& aPayload,
                          TUint16 aInterface)
    {
    iTransportLayer->DataOutL(aConnectionId, aReportId, aInterface, aPayload);    
    }


// ---------------------------------------------------------------------------
// From MDriverAccess
// GetIdle()
// ---------------------------------------------------------------------------
//
void CGenericHid::GetIdleL(TInt aConnectionId, TUint8 aReportId,
    TUint16 aInterface )
    {
    iTransportLayer->GetIdleL(aConnectionId, aReportId, aInterface);    
    }

// ---------------------------------------------------------------------------
// From MDriverAccess
// SetIdle()
// ---------------------------------------------------------------------------
//
void CGenericHid::SetIdleL(TInt aConnectionId, TUint8 aDuration,
    TUint8 aReportId, TUint16 aInterface, CHidDriver* aDriver)
    {
    iTransportLayer->SetIdleL(aConnectionId, aDuration, aReportId, aInterface);
    CConnectionInfo* conninfo = SeekConnectionInfo( aConnectionId );
    if ( conninfo )
        {
        conninfo->SetLastCommandHandler(aDriver);
        }          
                       
    }

// ---------------------------------------------------------------------------
// RemoveDrivers()
// ---------------------------------------------------------------------------
//
void CGenericHid::RemoveDrivers()
    {
    TRACE_FUNC
    // Driver instances
    CDriverListItem* driverItem;
    while ( !iDriverList.IsEmpty() )
        {
        driverItem = iDriverList.Last();
        iDriverList.Remove( *driverItem );
        delete driverItem;
        }
    }

// ---------------------------------------------------------------------------
// From CHidTransport
// Disconnected()
// ---------------------------------------------------------------------------
//
TInt CGenericHid::Disconnected( TInt aConnectionId )
    {
    TRACE_FUNC_ENTRY
    TInt retVal = KErrNone;
    
    TSglQueIter<CDriverListItem> driverIter( iDriverList );
    driverIter.SetToFirst();    

    CDriverListItem* driverItem = driverIter;    
    while ( driverItem )
        {            
        driverIter++;    
        if ( driverItem->ConnectionId() == aConnectionId )
            {
            TRACE_INFO(_L("[HID]\tCGenericHid::Disconnected driver"));
            if (driverItem->Driver())
                {
                driverItem->Driver()->Disconnected(0);
                }
            // Remove it from the list of driver instances           
            
            iDriverList.Remove(*driverItem);
            delete driverItem;
            driverItem = NULL;
            retVal = KErrNone;
            }                                  
        driverItem = driverIter;
        
        TRACE_INFO(_L("[HID]\tCGenericHid::Disconnected next driver"));
        }
    TRACE_INFO(_L("[HID]\tCGenericHid::Disconnected remove connection info"));
    TInt count = iConnectionInfo.Count();
    for (TInt i = count-1 ; i>=0; i--)
        {
        TRACE_INFO((_L("[HID]\tCGenericHid::Disconnected remove connection info %d"),i));
        CConnectionInfo* conninfo = iConnectionInfo[i];
        TRACE_INFO((_L("[HID]\tCGenericHid::Disconnected remove connection info %d"),i));
        if ( conninfo->ConnectionID() == aConnectionId )                
            {
            iConnectionInfo.Remove(i);
            delete conninfo;
            TRACE_INFO((_L("[HID]\tCGenericHid::Disconnected remove connection info %d removed"),i));
            }
        }     
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// From CHidTransport
// ConnectedL
// HID device has been connected.  Attempt to find a driver that can
// handle reports in the format specified by the report descriptor.
// ---------------------------------------------------------------------------
//
TInt CGenericHid::ConnectedL( TInt aConnectionId, const TDesC8& aDescriptor )
    {
    TRACE_INFO((_L("[HID]\tCGenericHid::ConnectedL(%d, ...)"), aConnectionId))    
    
    // Place the parsed report descriptor in the driver list item:
    
    TBool found = EFalse;
    CConnectionInfo* conninfo = SeekConnectionInfo( aConnectionId );
    if ( conninfo )
        {
        return KErrInUse;    
        }
    
    CReportRoot* reportRoot = iParser->ParseL( aDescriptor );
    CleanupStack::PushL(reportRoot);
        
    TRACE_INFO(_L("[HID]\tCGenericHid::ConnectedL: evaluate driver array"));
    // Implementation info array
    RImplInfoPtrArray implInfoArray;
    REComSession::ListImplementationsL( KHidDriverPluginInterfaceUid, implInfoArray );
    CleanupClosePushL(implInfoArray);    
    
    TRACE_INFO((_L("[HID]\tCGenericHid::ConnectedL: %d implementations found"), implInfoArray.Count()));
    TInt index = 0;
    TInt retVal = KErrHidNoDriver;
    TInt supportedfields = 0;
    CHidDriver* driver = NULL;
    for ( index  = 0; index < implInfoArray.Count(); index++ )
        {
        // parse implementation UID
        CImplementationInformation* info = implInfoArray[ index  ];
        TUid implUid = info->ImplementationUid();
        TRACE_INFO((_L("[HID]\tCGenericHid::ConnectedL: load plugin 0x%08x"),implUid ));
        // load driver
        // Trap so other drivers will be enumerated even if
        // this fails:

        TRAPD(retTrap, driver = CHidDriver::NewL( implUid, this ));
        if ( retTrap != KErrNone)
            {
            continue;    
            }
        CleanupStack::PushL(driver);
        TRACE_INFO((_L("[HID]\tCGenericHid::ConnectedL: init plugin 0x%08x"),implUid ));
        driver->InitialiseL( aConnectionId );
        TInt ret = driver->CanHandleReportL( reportRoot );
        if (ret == KErrNone)
            {
            TRACE_INFO(_L("[HID]\tCGenericHid::ConnectedL(): found driver"));            
	        
	        // Make a new driver list item:
	        CDriverListItem* driverItem = new ( ELeave ) CDriverListItem( aConnectionId );	        
	        CleanupStack::PushL( driverItem );	                
	        driver->SetInputHandlingReg( iInputHandlingReg );
	        supportedfields += driver->SupportedFieldCount();	        
            iDriverList.AddLast( *driverItem );
            CleanupStack::Pop( driverItem );
            driverItem->SetDriver( driver );    
            CleanupStack::Pop( driver );
            retVal = KErrNone;
            found = ETrue;
            }
        else
        	{
 	        CleanupStack::PopAndDestroy( driver );
        	}
        }
    TRACE_INFO((_L("[HID]\tCGenericHid::ConnectedL Partial supported hid device supported %d in report %d&"),supportedfields,iParser->FieldCount()));
    if (supportedfields < iParser->FieldCount() && found )
        {
        TRACE_INFO(_L("[HID]\tCGenericHid::ConnectedL Partial supported hid device"));
        }
    implInfoArray.ResetAndDestroy();     
    CleanupStack::PopAndDestroy();  // info
    if ( found )
        {   
        TRACE_INFO(_L("[HID]\tCGenericHid::ConnectedL append connection info"));    
        conninfo = CConnectionInfo::NewL(aConnectionId, reportRoot);
        CleanupStack::Pop(reportRoot); // ownership transfered to conninfo        
        CleanupStack::PushL(conninfo);
        iConnectionInfo.AppendL(conninfo);
        CleanupStack::Pop(conninfo);
        }         
    else
        {
        CleanupStack::PopAndDestroy(reportRoot);     
        }
    
    return retVal;
    }

// ---------------------------------------------------------------------------
// From CHidTransport
// DataIn
// Determine which driver is handling this connection ID and pass the payload
// reference to it
// ---------------------------------------------------------------------------
//
TInt CGenericHid::DataIn(TInt aConnectionId,
    CHidTransport::THidChannelType aChannel, const TDesC8& aPayload)
    {
    TRACE_FUNC_ENTRY
    TInt retVal = KErrHidNoDriver;
    TInt ret = KErrNone;
    
    TSglQueIter<CDriverListItem> driverIter( iDriverList );
    driverIter.SetToFirst();    

    CDriverListItem* item = driverIter;
    TBool found = EFalse; 
    while ( item )
        {            
        if ( item->ConnectionId() == aConnectionId )
                {                
                ret = item->Driver()->DataIn( aChannel, aPayload );
                if (ret == KErrNone)
                    {
                    TRACE_INFO(_L("[HID]\tCGenericHid::DataIn command handled"));
                    found = ETrue;
                    retVal = KErrNone;
                    }
                }
         TRACE_INFO(_L("[HID]\tCGenericHid::DataIn next driver"));
         driverIter++;
         item = driverIter;
         }
    if ( !found && aChannel == CHidTransport::EHidChannelCtrl )
        {
        retVal = KErrNone;
        }
    iInputHandlingReg->Reset();    
    TRACE_FUNC_EXIT    
    return retVal;
    }


// ---------------------------------------------------------------------------
// ReportDescriptor
// Provides access to the parsed results to the factory
// ---------------------------------------------------------------------------
//
CReportRoot* CGenericHid::ReportDescriptor(TInt aConnectionId)
    {
    CConnectionInfo* conninfo = SeekConnectionInfo( aConnectionId );
    if ( conninfo )
        {
        return conninfo->ReportRoot();
        }
    return NULL;
    }

// ---------------------------------------------------------------------------
// From CHidTransport
// DriverActive()
// ---------------------------------------------------------------------------
//
TInt CGenericHid::DriverActive(TInt aConnectionId,
    CHidTransport::TDriverState aActive)
    {
    TRACE_FUNC_ENTRY
    TInt retVal = KErrHidNoDriver;    
    // Find the driver handling the connection and stop it    
    TSglQueIter<CDriverListItem> driverIter( iDriverList );
    driverIter.SetToFirst();  
    CDriverListItem* item = driverIter;
    
    while ( item )
        {
        TRACE_INFO(_L("[HID]\tCGenericHid::DriverActive"));        
        if ( item->ConnectionId() == aConnectionId && item->Driver() )
            {
            TRACE_INFO(_L("[HID]\tCGenericHid::DriverActive driver found"));
            if ( aActive == CHidTransport::EActive )
                {
                TRAP(retVal, item->Driver()->StartL( aConnectionId ));
                if (retVal != KErrNone)
                    {
                    break;
                    }
                }
            else if ( aActive == CHidTransport::ESuspend)
                {
                item->Driver()->Stop();
                retVal = KErrNone;
                }            
            }   
         driverIter++;
         item = driverIter;
         }
    TRACE_FUNC_EXIT
    return retVal;
    }

// ---------------------------------------------------------------------------
// CommandResult()
// ---------------------------------------------------------------------------
//
void CGenericHid::CommandResult(TInt aConnectionId, TInt aCmdAck)
    {
    // Get the driver handling this connection    
    CConnectionInfo* conninfo = SeekConnectionInfo( aConnectionId );
    if ( conninfo )
        {
        CHidDriver*  hiddriver = conninfo->ReturnLastCommandHandler();
        if (hiddriver)
            {
            hiddriver->CommandResult(aCmdAck);
            }
        }    
    }

// ---------------------------------------------------------------------------
// SeekConnectionInfo()
// ---------------------------------------------------------------------------
//
CConnectionInfo* CGenericHid::SeekConnectionInfo(TInt aConnectionId)
    {
    TRACE_FUNC    
    CConnectionInfo* conninfo = NULL;
    TInt count = iConnectionInfo.Count();
    TRACE_INFO((_L("[HID]\tCGenericHid::SeekConnectionInfo count %d"), count));   
    for (TInt i = 0 ; i < count; i++)
        {
        conninfo = iConnectionInfo[i];
        TRACE_INFO((_L("[HID]\tCGenericHid::SeekConnectionInfo connection info check %d %d"),aConnectionId, conninfo->ConnectionID()));    
        if ( conninfo->ConnectionID() == aConnectionId)                
            {
            TRACE_INFO(_L("[HID]\tCGenericHid::SeekConnectionInfo connection info found"));    
            return conninfo;
            }
        }
    return NULL;
    }