/*
* Copyright (c) 2007-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 <e32base.h>
#include "usbhoststack.h"
#include "fdfapi.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "sessionTraces.h"
#endif
/**
Starts the server process.
*/
static TInt StartServer()
{
OstTraceFunctionEntry0( _FDF_STARTSERVER_ENTRY );
const TUidType serverUid(KNullUid, KNullUid, KUsbFdfUid);
//
// EPOC and EKA2 is easy, we just create a new server process. Simultaneous
// launching of two such processes should be detected when the second one
// attempts to create the server object, failing with KErrAlreadyExists.
//
RProcess server;
TInt err = server.Create(KUsbFdfImg, KNullDesC, serverUid);
OstTrace1( TRACE_NORMAL, _FDF_STARTSERVER, "\terr = %d", err );
if ( err != KErrNone )
{
OstTraceFunctionExit0( _FDF_STARTSERVER_EXIT );
return err;
}
TRequestStatus stat;
server.Rendezvous(stat);
if ( stat != KRequestPending )
{
OstTrace0( TRACE_NORMAL, _FDF_STARTSERVER_DUP1, "\taborting startup" );
server.Kill(0); // abort startup
}
else
{
OstTrace0( TRACE_NORMAL, _FDF_STARTSERVER_DUP2, "\tresuming" );
server.Resume(); // logon OK - start the server
}
User::WaitForRequest(stat); // wait for start or death
// we can't use the 'exit reason' if the server panicked as this
// is the panic 'reason' and may be '0' which cannot be distinguished
// from KErrNone
OstTrace1( TRACE_NORMAL, _FDF_STARTSERVER_DUP3, "\tstat.Int = %d", stat.Int());
err = (server.ExitType() == EExitPanic) ? KErrServerTerminated : stat.Int();
server.Close();
OstTrace1( TRACE_NORMAL, _FDF_STARTSERVER_DUP4, "\terr = %d", err );
OstTraceFunctionExit0( _FDF_STARTSERVER_EXIT_DUP1 );
return err;
}
EXPORT_C RUsbHostStack::RUsbHostStack()
// these are all arbitrary initialisations
: iDeviceEventPckg(TDeviceEventInformation()),
iDevmonEventPckg(0)
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_RUSBHOSTSTACK_ENTRY );
OstTrace0( TRACE_NORMAL, RUSBHOSTSTACK_RUSBHOSTSTACK, "*** Search on '***USB HOST STACK' to find device events." );
}
EXPORT_C TVersion RUsbHostStack::Version() const
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_VERSION_ENTRY );
return(TVersion( KUsbFdfSrvMajorVersionNumber,
KUsbFdfSrvMinorVersionNumber,
KUsbFdfSrvBuildNumber
)
);
}
EXPORT_C TInt RUsbHostStack::Connect()
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_CONNECT_ENTRY );
TInt err = DoConnect();
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_CONNECT, "\terr = %d", err);
return err;
}
/**
Connects the session, starting the server if necessary
@return Error.
*/
TInt RUsbHostStack::DoConnect()
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_DOCONNECT_ENTRY);
TInt retry = 2;
FOREVER
{
// Use message slots from the global pool.
TInt err = CreateSession(KUsbFdfServerName, Version(), -1);
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_DOCONNECT, "\terr = %d", err );
if ((err != KErrNotFound) && (err != KErrServerTerminated))
{
OstTrace0( TRACE_NORMAL, RUSBHOSTSTACK_DOCONNECT_DUP1, "\treturning after CreateSession" );
OstTraceFunctionExit0( RUSBHOSTSTACK_DOCONNECT_EXIT);
return err;
}
if (--retry == 0)
{
OstTrace0( TRACE_NORMAL, RUSBHOSTSTACK_DOCONNECT_DUP2, "\treturning after running out of retries" );
OstTraceFunctionExit0( RUSBHOSTSTACK_DOCONNECT_EXIT_DUP1 );
return err;
}
err = StartServer();
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_DOCONNECT_DUT3, "\terr = %d", err );
if ((err != KErrNone) && (err != KErrAlreadyExists))
{
OstTrace0( TRACE_NORMAL, RUSBHOSTSTACK_DOCONNECT_DUP4, "\treturning after StartServer" );
OstTraceFunctionExit0( RUSBHOSTSTACK_DOCONNECT_EXIT_DUP2 );
return err;
}
}
}
EXPORT_C TInt RUsbHostStack::EnableDriverLoading()
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_ENABLEDRIVERLOADING_ENTRY );
TInt ret = SendReceive(EUsbFdfSrvEnableDriverLoading);
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_ENABLEDRIVERLOADING, "\tret = %d", ret );
OstTraceFunctionExit0( RUSBHOSTSTACK_ENABLEDRIVERLOADING_EXIT );
return ret;
}
EXPORT_C void RUsbHostStack::DisableDriverLoading()
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_DISABLEDRIVERLOADING_ENTRY );
TInt ret = SendReceive(EUsbFdfSrvDisableDriverLoading);
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_DISABLEDRIVERLOADING, "\tret = %d", ret );
(void)ret;
OstTraceFunctionExit0( RUSBHOSTSTACK_DISABLEDRIVERLOADING_EXIT );
}
EXPORT_C void RUsbHostStack::NotifyDeviceEvent(TRequestStatus& aStat, TDeviceEventInformation& aDeviceEventInformation)
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_NOTIFYDEVICEEVENT_ENTRY );
TIpcArgs args;
iDeviceEventPckg.Set((TUint8*)&aDeviceEventInformation, sizeof(TDeviceEventInformation), sizeof(TDeviceEventInformation));
args.Set(0, &iDeviceEventPckg);
SendReceive(EUsbFdfSrvNotifyDeviceEvent, args, aStat);
OstTraceFunctionExit0( RUSBHOSTSTACK_NOTIFYDEVICEEVENT_EXIT );
}
EXPORT_C void RUsbHostStack::NotifyDeviceEventCancel()
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_NOTIFYDEVICEEVENTCANCEL_ENTRY );
TInt ret = SendReceive(EUsbFdfSrvNotifyDeviceEventCancel);
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_NOTIFYDEVICEEVENTCANCEL, "\tret = %d", ret);
(void)ret;
OstTraceFunctionExit0( RUSBHOSTSTACK_NOTIFYDEVICEEVENTCANCEL_EXIT );
}
EXPORT_C void RUsbHostStack::NotifyDevmonEvent(TRequestStatus& aStat, TInt& aEvent)
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_NOTIFYDEVMONEVENT_ENTRY );
TIpcArgs args;
iDevmonEventPckg.Set((TUint8*)&aEvent, sizeof(TInt), sizeof(TInt));
args.Set(0, &iDevmonEventPckg);
SendReceive(EUsbFdfSrvNotifyDevmonEvent, args, aStat);
OstTraceFunctionExit0( RUSBHOSTSTACK_NOTIFYDEVMONEVENT_EXIT );
}
EXPORT_C void RUsbHostStack::NotifyDevmonEventCancel()
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_NOTIFYDEVMONEVENTCANCEL_ENTRY );
TInt ret = SendReceive(EUsbFdfSrvNotifyDevmonEventCancel);
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_NOTIFYDEVMONEVENTCANCEL, "\tret = %d", ret);
(void)ret;
OstTraceFunctionExit0( RUSBHOSTSTACK_NOTIFYDEVMONEVENTCANCEL_EXIT );
}
EXPORT_C TInt RUsbHostStack::GetSupportedLanguages(TUint aDeviceId, RArray<TUint>& aLangIds)
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_GETSUPPORTEDLANGUAGES_ENTRY );
aLangIds.Reset();
TUint singleLangIdOrNumLangs = 0;
TPckg<TUint> singleLangIdOrNumLangsBuf(singleLangIdOrNumLangs);
TInt ret = SendReceive(EUsbFdfSrvGetSingleSupportedLanguageOrNumberOfSupportedLanguages, TIpcArgs(aDeviceId, &singleLangIdOrNumLangsBuf));
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_GETSUPPORTEDLANGUAGES, "\tsingleLangIdOrNumLangs = %d", singleLangIdOrNumLangs);
switch ( ret )
{
case KErrNotFound:
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_GETSUPPORTEDLANGUAGES_DUP1, "\tThere is no language available or the wrong device id %d was supplied",aDeviceId);
ret = KErrNotFound;
break;
case KErrNone:
// The buffer is now either empty or contains the single supported language ID
ret = CopyLangIdsToArray(aLangIds, singleLangIdOrNumLangsBuf);
break;
case KErrTooBig:
{
// The buffer now contains the number of supported languages (not 0 or 1).
// Lang IDs are TUints.
RBuf8 buf;
ret = buf.Create(singleLangIdOrNumLangs * sizeof(TUint));
if ( ret == KErrNone )
{
ret = SendReceive(EUsbFdfSrvGetSupportedLanguages, TIpcArgs(aDeviceId, &buf));
if ( ret == KErrNone )
{
ret = CopyLangIdsToArray(aLangIds, buf);
}
buf.Close();
}
}
break;
default:
// Regular failure.
break;
}
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_GETSUPPORTEDLANGUAGES_DUP2, "\tret = %d", ret);
OstTraceFunctionExit0( RUSBHOSTSTACK_GETSUPPORTEDLANGUAGES_EXIT );
return ret;
}
TInt RUsbHostStack::CopyLangIdsToArray(RArray<TUint>& aLangIds, const TDesC8& aBuffer)
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_COPYLANGIDSTOARRAY_ENTRY );
ASSERT(!(aBuffer.Size() % 4));
const TUint numLangs = aBuffer.Size() / 4;
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_COPYLANGIDSTOARRAY, "\tnumLangs = %d", numLangs );
TInt ret = KErrNone;
const TUint* ptr = reinterpret_cast<const TUint*>(aBuffer.Ptr());
for ( TUint ii = 0 ; ii < numLangs ; ++ii )
{
ret = aLangIds.Append(*ptr++); // increments by sizeof(TUint)
if ( ret )
{
aLangIds.Reset();
break;
}
}
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_COPYLANGIDSTOARRAY_DUP1, "\tret = %d", ret );
OstTraceFunctionExit0( RUSBHOSTSTACK_COPYLANGIDSTOARRAY_EXIT );
return ret;
}
EXPORT_C TInt RUsbHostStack::GetManufacturerStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString)
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_GETMANUFACTURERSTRINGDESCRIPTOR_ENTRY );
TInt ret = SendReceive(EUsbFdfSrvGetManufacturerStringDescriptor, TIpcArgs(aDeviceId, aLangId, &aString));
if ( !ret )
{
OstTraceExt1( TRACE_NORMAL, RUSBHOSTSTACK_GETMANUFACTURERSTRINGDESCRIPTOR, "RUsbHostStack::GetManufacturerStringDescriptor;aString=%S", aString );
}
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_GETMANUFACTURERSTRINGDESCRIPTOR_DUP1, "\tret = %d", ret );
OstTraceFunctionExit0( RUSBHOSTSTACK_GETMANUFACTURERSTRINGDESCRIPTOR_EXIT );
return ret;
}
EXPORT_C TInt RUsbHostStack::GetProductStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString)
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_GETPRODUCTSTRINGDESCRIPTOR_ENTRY );
TInt ret = SendReceive(EUsbFdfSrvGetProductStringDescriptor, TIpcArgs(aDeviceId, aLangId, &aString));
if ( !ret )
{
OstTraceExt1( TRACE_NORMAL, RUSBHOSTSTACK_GETPRODUCTSTRINGDESCRIPTOR, "\taString = \"%S\"", aString );
}
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_GETPRODUCTSTRINGDESCRIPTOR_DUP1, "\tret = %d", ret );
OstTraceFunctionExit0( RUSBHOSTSTACK_GETPRODUCTSTRINGDESCRIPTOR_EXIT );
return ret;
}
EXPORT_C TInt RUsbHostStack::GetOtgDescriptor(TUint aDeviceId, TOtgDescriptor& aDescriptor)
{
OstTraceFunctionEntry0( RUSBHOSTSTACK_GETOTGDESCRIPTOR_ENTRY );
TPckg<TOtgDescriptor> otgDescriptorPckg(aDescriptor);
TIpcArgs args;
args.Set(0, aDeviceId);
args.Set(1, &otgDescriptorPckg);
TInt ret = SendReceive(EUsbFdfSrvGetOtgDescriptor, args);
if ( !ret )
{
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_GETOTGDESCRIPTOR, "\taDescriptor.iDeviceId = %d", aDescriptor.iDeviceId );
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_GETOTGDESCRIPTOR_DUP1, "\taDescriptor.iAttributes = %d", aDescriptor.iAttributes );
}
OstTrace1( TRACE_NORMAL, RUSBHOSTSTACK_GETOTGDESCRIPTOR_DUP2, "\tret = %d", ret );
OstTraceFunctionExit0( RUSBHOSTSTACK_GETOTGDESCRIPTOR_EXIT );
return ret;
}
EXPORT_C TInt RUsbHostStack::__DbgFailNext(TInt aCount)
{
#ifdef _DEBUG
return SendReceive(EUsbFdfSrvDbgFailNext, TIpcArgs(aCount));
#else
(void)aCount;
return KErrNone;
#endif
}
EXPORT_C TInt RUsbHostStack::__DbgAlloc()
{
#ifdef _DEBUG
return SendReceive(EUsbFdfSrvDbgAlloc);
#else
return KErrNone;
#endif
}