tsrc/testtools/usbman_stub/usbman/client/src/RUsb.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:20:49 +0100
branchRCL_3
changeset 80 e02eb84a14d2
parent 77 5b2a402e96ac
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* 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:
*
*/

#include <e32uid.h>
#include <f32file.h>
#include <usbman.h>
#include <usb.h>
#include <e32base.h>
#include "rusb.h"
#include <usb/usblogger.h>
#include <stubber.h>
#include "usbmandll_stub.h"
#include <usbpersonalityids.h>

#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, "USBMAN");
#endif

#ifdef __USBMAN_NO_PROCESSES__
#include <e32math.h>
#endif

// CONSTANTS
//const TUint KUsbAllStates = 0xFFFFFFFF;

_LIT8(KLogStub, "[USBMAN] [Stub]");

static TInt StartServer()
//
// Start the server process or thread
//
	{
	const TUidType serverUid(KNullUid, KNullUid, KUsbmanSvrUid);

#ifdef __USBMAN_NO_PROCESSES__
	//
	// In EKA1 WINS the server is a DLL, the exported entrypoint returns a TInt
	// which represents the real entry-point for the server thread
	//
	RLibrary lib;
	TInt err = lib.Load(KUsbmanImg, serverUid);
	
	if (err != KErrNone)
		{
		return err;
		}

	TLibraryFunction ordinal1 = lib.Lookup(1);
	TThreadFunction serverFunc = reinterpret_cast<TThreadFunction>(ordinal1());

	//
	// To deal with the unique thread (+semaphore!) naming in EPOC, and that we may
	// be trying to restart a server that has just exited we attempt to create a
	// unique thread name for the server.
	// This uses Math::Random() to generate a 32-bit random number for the name
	//
	TName name(KUsbServerName);
	name.AppendNum(Math::Random(),EHex);
	
	RThread server;
	err = server.Create (
		name,
		serverFunc,
		KUsbmanStackSize,
		NULL,
		&lib,
		NULL,
		KUsbmanMinHeapSize,
		KUsbmanMaxHeapSize,
		EOwnerProcess
	);

	lib.Close();	// if successful, server thread has handle to library now
#else
	//
	// 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(KUsbmanImg, KNullDesC, serverUid);
#endif //__USBMAN_NO_PROCESSES__
	
	if (err != KErrNone)
		{
		return err;
		}

	TRequestStatus stat;
	server.Rendezvous(stat);
	
	if (stat!=KRequestPending)
		server.Kill(0);		// abort startup
	else
		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
	err = (server.ExitType() == EExitPanic) ? KErrServerTerminated : stat.Int();

	server.Close();
	
	LOGTEXT2(_L8("USB server started successfully: err = %d\n"),err);

	return err;
	}




EXPORT_C RUsb::RUsb() 
	: iDeviceStatePkg(0), iServiceStatePkg(0), iMessagePkg(0), 
	  iHostPkg(TDeviceEventInformation())
	{
	LOG_LINE
	LOG_FUNC
	}

EXPORT_C RUsb::~RUsb()
	{
	LOG_LINE
	LOG_FUNC
	}

EXPORT_C TVersion RUsb::Version() const
	{
	return(TVersion(KUsbSrvMajorVersionNumber,KUsbSrvMinorVersionNumber,KUsbSrvBuildVersionNumber));
	}

EXPORT_C TInt RUsb::Connect()
	{
	LOG_LINE
	LOG_FUNC

	TInt retry = 2;
	
	FOREVER
		{
		// Create the session to UsbSrv with 10 asynchronous message slots
		TInt err = CreateSession(KUsbServerName, Version(), 10);

		if ((err != KErrNotFound) && (err != KErrServerTerminated))
			{
			return err;
			}

		if (--retry == 0)
			{
			return err;
			}

		err = StartServer();		
		
		if ((err != KErrNone) && (err != KErrAlreadyExists))
			{
			return err;
			}
		}
	}

EXPORT_C void RUsb::Start(TRequestStatus& aStatus)
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbStart, aStatus);
	}

EXPORT_C void RUsb::StartCancel()
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbStartCancel);
	}

EXPORT_C void RUsb::Stop()
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbStop);
	}

EXPORT_C void RUsb::Stop(TRequestStatus& aStatus)
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbStop, aStatus);
	}

EXPORT_C void RUsb::StopCancel()
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbStopCancel);
	}

EXPORT_C TInt RUsb::GetServiceState(TUsbServiceState& aState)
	{
	LOG_LINE
	LOG_FUNC

	CStubber* stubber = CStubber::NewL();
	TApiBehavior beh( KUsbManStubAgentDll, EServiceState, 0, 0, KNullDesC8 );
	stubber -> InvokeApi( beh );

	delete stubber;
	stubber = NULL;

	if ( beh.iOutput != KNullDesC8 )
	    {           
	    if ( !beh.iOutput.Compare( _L8( "EUsbServiceIdle" ) ) )
	        aState = EUsbServiceIdle;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbServiceStarting" ) ) )
            aState = EUsbServiceStarting;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbServiceStarted" ) ) )
            aState = EUsbServiceStarted;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbServiceStopping" ) ) )
            aState = EUsbServiceStopping;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbServiceFatalError" ) ) )
            aState = EUsbServiceFatalError;
	    else
	    	{}
	    }
    else
        {
		TPckg<TUint32> pkg(aState);
		TInt ret=SendReceive(EUsbGetCurrentState, TIpcArgs(&pkg));
		aState=(TUsbServiceState)pkg();
		return ret;
        }
	return beh.iCompleteCode;
	}

EXPORT_C TInt RUsb::GetCurrentState(TUsbServiceState& aState)
	{
	LOG_LINE
	LOG_FUNC

	return GetServiceState(aState);
	}

EXPORT_C void RUsb::ServiceStateNotification(TUsbServiceState& aState,
	TRequestStatus& aStatus)
	{
	LOG_LINE
	LOG_FUNC

	iServiceStatePkg.Set((TUint8*)&aState, sizeof(TUint32), sizeof(TUint32));

	SendReceive(EUsbRegisterServiceObserver, TIpcArgs(&iServiceStatePkg), aStatus);
	}

EXPORT_C void RUsb::ServiceStateNotificationCancel()
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbCancelServiceObserver);
	}

EXPORT_C TInt RUsb::GetDeviceState(TUsbDeviceState& aState)
	{
	LOG_LINE
	LOG_FUNC

	_LIT8( KLogStubConfigured, "[USBMAN] [StubConfigured]");
	CUsbLog::Write(KLogStub, KNullDesC8());
	
	CStubber* stubber = CStubber::NewL();
	TApiBehavior beh( KUsbManStubAgentDll, EGetDeviceState, 0, 0, KNullDesC8 );
	stubber -> InvokeApi( beh );

	delete stubber;
	stubber = NULL;

	if ( beh.iOutput != KNullDesC8 )
	    {           
	    CUsbLog::Write(KLogStub, KNullDesC8());
	    if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateUndefined" ) ) )
	        aState = EUsbDeviceStateUndefined;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateDefault" ) ) )
            aState = EUsbDeviceStateDefault;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateAttached" ) ) )
            aState = EUsbDeviceStateAttached;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStatePowered" ) ) )
            aState = EUsbDeviceStatePowered;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateConfigured" ) ) )
	    	{
            aState = EUsbDeviceStateConfigured;
    	    CUsbLog::Write(KLogStubConfigured, KNullDesC8());
	    	}
	    else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateAddress" ) ) )
            aState = EUsbDeviceStateAddress;
	    else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateSuspended" ) ) )
            aState = EUsbDeviceStateSuspended;
	    else
	    	{}
	    }
    else
        {
        _LIT8(KLogNoStub, "[USBMAN] [NoStub]");
        CUsbLog::Write(KLogNoStub, KNullDesC8());
		TPckg<TUint32> pkg(aState);
		TInt ret=SendReceive(EUsbGetCurrentDeviceState, TIpcArgs(&pkg));
		aState=(TUsbDeviceState)pkg();
		return ret;
        }
		
	return beh.iCompleteCode;
	}

EXPORT_C void RUsb::DeviceStateNotification(TUint aEventMask, TUsbDeviceState& aState,
											TRequestStatus& aStatus)
	{
	LOG_LINE
	LOG_FUNC

    CUsbLog::Write(KLogStub, KNullDesC8());
    CStubber* stubber = CStubber::NewL();
    TApiBehavior beh( KUsbManStubAgentDll, EDeviceStateNotification, 0, 0, KNullDesC8 );
    stubber -> InvokeApi( beh );

    delete stubber;
    stubber = NULL;
    
    TRequestStatus* stat = &aStatus;
    
    if ( beh.iOutput != KNullDesC8 )
        {                        
        if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateUndefined" ) ) )
            aState = EUsbDeviceStateUndefined;
        else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateDefault" ) ) )
            aState = EUsbDeviceStateDefault;
        else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateAttached" ) ) )
            aState = EUsbDeviceStateAttached;
        else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStatePowered" ) ) )
            aState = EUsbDeviceStatePowered;
        else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateConfigured" ) ) )
            aState = EUsbDeviceStateConfigured;
        else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateAddress" ) ) )
            aState = EUsbDeviceStateAddress;
        else if ( !beh.iOutput.Compare( _L8( "EUsbDeviceStateSuspended" ) ) )
            aState = EUsbDeviceStateSuspended;
        else
            {}
        User::RequestComplete( stat, beh.iAsyncCompleteCode );
        }
    else
        {
        iDeviceStatePkg.Set((TUint8*)&aState, sizeof(TUint32), sizeof(TUint32));
        SendReceive(EUsbRegisterObserver, TIpcArgs(aEventMask, &iDeviceStatePkg), aStatus);
        }

	}

EXPORT_C void RUsb::DeviceStateNotificationCancel()
	{
	LOG_LINE
	LOG_FUNC

    CStubber* stubber = CStubber::NewL();
    TApiBehavior beh( KUsbManStubAgentDll, EDeviceStateNotificationCancel, 0, 0, KNullDesC8 );
    stubber -> InvokeApi( beh );

    delete stubber;
    stubber = NULL;
    
    if ( beh.iOutput != KNullDesC8 )
        {        
        
        }
    else 
    	{
    	SendReceive(EUsbCancelObserver);
    	}
	}

EXPORT_C void RUsb::StateNotification(TUint aEventMask, TUsbDeviceState& aState, TRequestStatus& aStatus)
	{
	LOG_LINE
	LOG_FUNC

	DeviceStateNotification(aEventMask, aState, aStatus);
	}

EXPORT_C void RUsb::StateNotificationCancel()
	{
	LOG_LINE
	LOG_FUNC

	DeviceStateNotificationCancel();
	}
	
EXPORT_C void RUsb::TryStart(TInt aPersonalityId, TRequestStatus& aStatus)
	{
	LOG_LINE
	LOG_FUNC

    CStubber* stubber = CStubber::NewL();
    TApiBehavior beh( KUsbManStubAgentDll, ETryStartAsync, 0, 0, KNullDesC8 );
    stubber -> InvokeApi( beh );
    
    delete stubber;
    stubber = NULL;
    
    if ( beh.iOutput != KNullDesC8 )
        {
        TRequestStatus* stat = &aStatus;
        User::RequestComplete( stat, beh.iAsyncCompleteCode );
        }
    else
        {    
		TIpcArgs ipcArgs(aPersonalityId);
		SendReceive(EUsbTryStart, ipcArgs, aStatus);
        }
	}

EXPORT_C void RUsb::TryStop(TRequestStatus& aStatus)
	{
	LOG_LINE
	LOG_FUNC

    CStubber* stubber = CStubber::NewL();
    TApiBehavior beh( KUsbManStubAgentDll, ETryStopAsync, 0, 0, KNullDesC8 );
    stubber -> InvokeApi( beh );
    
    delete stubber;
    stubber = NULL;
    
    if ( beh.iOutput != KNullDesC8 )
        {
        TRequestStatus* stat = &aStatus;
        User::RequestComplete( stat, beh.iAsyncCompleteCode );
        }
    else
    	SendReceive(EUsbTryStop, aStatus);
	}
	
EXPORT_C TInt RUsb::CancelInterest(TUsbReqType aMessageId)
	{
	LOG_LINE
	LOG_FUNC

    CStubber* stubber = CStubber::NewL();
    TApiBehavior beh( KUsbManStubAgentDll, ECancelInterest, 0, 0, KNullDesC8 );
    stubber -> InvokeApi( beh );
    
    delete stubber;
    stubber = NULL;
	
    if ( beh.iOutput != KNullDesC8 )
        {
        
        }
    else
        {
		TInt messageId;
		switch (aMessageId)
			{
		case EStart:
			messageId = EUsbStart;
			break;
		case EStop:
			messageId = EUsbStop;
			break;
		case ETryStart:
			messageId = EUsbTryStart;
			break;
		case ETryStop:
			messageId = EUsbTryStop;
			break;
		default:
			return KErrNotSupported;
			}
			
		TIpcArgs ipcArgs(messageId);
		return SendReceive(EUsbCancelInterest, ipcArgs);
        }

    return beh.iCompleteCode;
	}

EXPORT_C TInt RUsb::GetDescription(TInt aPersonalityId, HBufC*& aLocalizedPersonalityDescriptor)
	{
	LOG_LINE
	LOG_FUNC

	TInt ret = KErrNone;
	// caller is responsible for freeing up memory allocatd for aLocalizedPersonalityDescriptor
	TRAP(ret, aLocalizedPersonalityDescriptor = HBufC::NewL(KUsbStringDescStringMaxSize));
	if (ret == KErrNone)
		{
		TPtr ptr = aLocalizedPersonalityDescriptor->Des();
		TIpcArgs ipcArgs(0, &ptr);
		ipcArgs.Set(0, aPersonalityId);
		ret = SendReceive(EUsbGetDescription, ipcArgs);
		}
	else
		{
		// just in case caller tries to free the memory before checking the return code
		aLocalizedPersonalityDescriptor = NULL;
		}

	return ret;	
	}
	
EXPORT_C TInt RUsb::GetCurrentPersonalityId(TInt& aPersonalityId)
	{
	LOG_LINE
	LOG_FUNC

    CUsbLog::Write(KLogStub, KNullDesC8());
    CStubber* stubber = CStubber::NewL();
    TApiBehavior beh( KUsbManStubAgentDll, EGetCurrentPersonalityId, 0, 0, KNullDesC8 );
    stubber -> InvokeApi( beh );
    
    delete stubber;
    stubber = NULL;    
    
    if ( beh.iOutput != KNullDesC8 )
        {
        if ( !beh.iOutput.Compare( _L8( "KUsbPersonalityIdPCSuite" ) ) )
            aPersonalityId = KUsbPersonalityIdPCSuite;
        else if ( !beh.iOutput.Compare( _L8( "KUsbPersonalityIdMS" ) ) )
            aPersonalityId = KUsbPersonalityIdMS;
        else if ( !beh.iOutput.Compare( _L8( "KUsbPersonalityIdPTP" ) ) )
            aPersonalityId = KUsbPersonalityIdPTP;
        else if ( !beh.iOutput.Compare( _L8( "KUsbPersonalityIdMTP" ) ) )
            aPersonalityId = KUsbPersonalityIdMTP;
        else if ( !beh.iOutput.Compare( _L8( "KUsbPersonalityIdPCSuite" ) ) )
            aPersonalityId = KUsbPersonalityIdPCSuite;
        else
        	{}
        }
    else
        {
		TPckg<TInt> pkg0(aPersonalityId);
		TInt ret = SendReceive(EUsbGetCurrentPersonalityId, TIpcArgs(&pkg0));
		aPersonalityId = static_cast<TInt>(pkg0());
		return ret;	
        }

    return beh.iCompleteCode;
	}

EXPORT_C TInt RUsb::GetSupportedClasses(TInt aPersonalityId, RArray<TUid>& aClassUids)
	{
	LOG_LINE
	LOG_FUNC

	TInt ret = KErrNone;
	HBufC8* buf = NULL;
	// +1 for the actual count of personality ids
	TRAP(ret, buf = HBufC8::NewL((KUsbMaxSupportedClasses + 1)*sizeof (TInt32)));
	if (ret != KErrNone)
		{
		return ret;
		}

	TPtr8 ptr8 = buf->Des();
	ret = SendReceive(EUsbGetSupportedClasses, TIpcArgs(aPersonalityId, &ptr8));
		
	if (ret == KErrNone)
		{
		const TInt32* recvedIds = reinterpret_cast<const TInt32*>(buf->Ptr());
		if (!recvedIds)
			{
			delete buf;
			return KErrCorrupt;
			}
			
		TInt arraySize = *recvedIds++;
		// Copy received supported class ids to aClassUids
		for (TInt i = 0; i < arraySize; i++)
			{
			if (recvedIds)
				{
				ret = aClassUids.Append(TUid::Uid(*recvedIds++));
				if(ret!=KErrNone)
					{
					//Remove all the ids appended so far (assume the last append failed, because
					//the only reason to fail is if the array couldn't grow to accommodate another
					//element).
					//It would be easier to just reset the array, but we never specified that
					//aClassUids should be an empty array, nor did we specify that this method
					//might empty the array. To maintain exisiting behaviour we should return
					//aClassUids to the state it was in when this method was called.
					TInt last = aClassUids.Count() - 1;
					while(i>0)
						{
						aClassUids.Remove(last);
						i--;
						last--;
						}	
					break;
					}
				}
			else
				{
				ret = KErrCorrupt;
				break;
				}
			}
		}
		
	delete buf;
	return ret;
	}
	
EXPORT_C TInt RUsb::ClassSupported(TInt aPersonalityId, TUid aClassUid, TBool& aSupported)
	{
	LOG_LINE
	LOG_FUNC

	TPckg<TInt32>  	pkg2(aSupported);
	TIpcArgs ipcArgs(aPersonalityId, aClassUid.iUid, &pkg2);
	
	TInt ret = SendReceive(EUsbClassSupported, ipcArgs);
	
	if (ret == KErrNone)
		{
		aSupported = static_cast<TBool>(pkg2());		
		}
		
	return ret;
	}
	
EXPORT_C TInt RUsb::GetPersonalityIds(RArray<TInt>& aPersonalityIds)
	{
	LOG_LINE
	LOG_FUNC

	TInt ret = KErrNone;
	HBufC8* buf = NULL;
	// +1 for the actual count of personality ids
	TRAP(ret, buf = HBufC8::NewL((KUsbMaxSupportedPersonalities + 1)*sizeof (TInt)));
	if (ret != KErrNone)
		{
		return ret;
		}

	TPtr8 ptr8 = buf->Des();
	ret = SendReceive(EUsbGetPersonalityIds, TIpcArgs(&ptr8));
		
	if (ret == KErrNone)
		{
		const TInt* recvedIds = reinterpret_cast<const TInt*>(buf->Ptr());
		if (!recvedIds)
			{
			delete buf;
			return KErrCorrupt;
			}
			
		TInt arraySize = *recvedIds++;
		// Copy received personality ids to aPersonalityIds
		for (TInt i = 0; i < arraySize; i++)
			{
			if (recvedIds)
				{		
				ret = aPersonalityIds.Append(*recvedIds++);
				
				if(ret!=KErrNone)
					{
					//Remove all the ids appended so far (assume the last append failed, because
					//the only reason to fail is if the array couldn't grow to accommodate another
					//element).
					//It would be easier to just reset the array, but we never specified that
					//aPersonalityIds should be an empty array, nor did we specify that this method
					//might empty the array. To maintain exisiting behaviour we should return
					//aPersonalityIds to the state it was in when this method was called.
					TInt last = aPersonalityIds.Count() - 1;
					while(i>0)
						{
						aPersonalityIds.Remove(last);
						i--;
						last--;
						}	
					break;
					}
				}
			else
				{
				ret = KErrCorrupt;
				break;
				}
			}
		}
		
	delete buf;
	return ret;
	}
	
EXPORT_C TInt RUsb::__DbgMarkHeap()
	{
#ifdef _DEBUG
    return SendReceive(EUsbDbgMarkHeap);
#else
    return KErrNone;
#endif
	}

EXPORT_C TInt RUsb::__DbgCheckHeap(TInt aCount)
	{
#ifdef _DEBUG
    return SendReceive(EUsbDbgCheckHeap, TIpcArgs(aCount));
#else
	(void)aCount; // not used for Release builds
    return KErrNone;
#endif
	}

EXPORT_C TInt RUsb::__DbgMarkEnd(TInt aCount)
	{
#ifdef _DEBUG
    return SendReceive(EUsbDbgMarkEnd, TIpcArgs(aCount));
#else
	(void)aCount; // not used for Release builds
    return KErrNone;
#endif
	}

EXPORT_C TInt RUsb::__DbgFailNext(TInt aCount)
	{
#ifdef _DEBUG
    return SendReceive(EUsbDbgFailNext, TIpcArgs(aCount));
#else
	(void)aCount; // not used for Release builds
    return KErrNone;
#endif
	}

EXPORT_C TInt RUsb::__DbgAlloc()
	{
#ifdef _DEBUG
    return SendReceive(EUsbDbgAlloc);
#else
    return KErrNone;
#endif
	}

EXPORT_C void panic()
	{
	_USB_PANIC(KUsbCliPncCat, EUsbPanicRemovedExport);
	}

EXPORT_C TInt RUsb::SetCtlSessionMode(TBool aValue)
	{
	LOG_LINE
	LOG_FUNC

//    CUsbLog::Write(KLogStub, KNullDesC8());
//    CStubber* stubber = CStubber::NewL();
//    TApiBehavior beh( KUsbManStubAgentDll, ESetCtlSessionMode, 0, 0, KNullDesC8 );
//    stubber -> InvokeApi( beh );
//    
//    delete stubber;
//    stubber = NULL;    
//    
//    if ( beh.iOutput != KNullDesC8 )
//        {
//        return KErrNone;
//        }
//    else
//        {
        TPckg<TBool> pkg(aValue);
        return SendReceive(EUsbSetCtlSessionMode, TIpcArgs(&pkg)); 
//        }
    
	}

EXPORT_C TInt RUsb::BusRequest()
	{
	LOG_LINE
	LOG_FUNC

	return SendReceive(EUsbBusRequest);
	}

EXPORT_C TInt RUsb::BusRespondSrp()
	{
	LOG_LINE
	LOG_FUNC

	return SendReceive(EUsbBusRespondSrp);
	}

EXPORT_C TInt RUsb::BusClearError()
	{
	LOG_LINE
	LOG_FUNC

	return SendReceive(EUsbBusClearError);
	}


EXPORT_C TInt RUsb::BusDrop()
	{
	LOG_LINE
	LOG_FUNC

	return SendReceive(EUsbBusDrop);
	}

EXPORT_C void RUsb::MessageNotification(TRequestStatus& aStatus, TInt& aMessage)
	{
	LOG_LINE
	LOG_FUNC

	iMessagePkg.Set((TUint8*)&aMessage, sizeof(TInt), sizeof(TInt));

	SendReceive(EUsbRegisterMessageObserver, TIpcArgs(&iMessagePkg), aStatus);
	}

EXPORT_C void RUsb::MessageNotificationCancel()
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbCancelMessageObserver);
	}

EXPORT_C void RUsb::HostEventNotification(TRequestStatus& aStatus,
										  TDeviceEventInformation& aDeviceInformation)
	{
	LOG_LINE
	LOG_FUNC

	iHostPkg.Set((TUint8*)&aDeviceInformation, sizeof(TDeviceEventInformation), sizeof(TDeviceEventInformation));

	SendReceive(EUsbRegisterHostObserver, TIpcArgs(&iHostPkg), aStatus);
	}
	
EXPORT_C void RUsb::HostEventNotificationCancel()
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbCancelHostObserver);
	}

EXPORT_C TInt RUsb::EnableFunctionDriverLoading()
	{
	LOG_LINE
	LOG_FUNC

	return SendReceive(EUsbEnableFunctionDriverLoading);
	}

EXPORT_C void RUsb::DisableFunctionDriverLoading()
	{
	LOG_LINE
	LOG_FUNC

	SendReceive(EUsbDisableFunctionDriverLoading);
	}

EXPORT_C TInt RUsb::GetSupportedLanguages(TUint aDeviceId, RArray<TUint>& aLangIds)
	{
	LOG_LINE
	LOG_FUNC

	aLangIds.Reset();

	TInt ret = KErrNone;
	HBufC8* buf = NULL;
	// +1 for the actual count of language ids
	TRAP(ret, buf = HBufC8::NewL((KUsbMaxSupportedLanguageIds + 1)*sizeof (TUint)));
	if (ret != KErrNone)
		{
		return ret;
		}

	TPtr8 ptr8 = buf->Des();
	ret = SendReceive(EUsbGetSupportedLanguages, TIpcArgs(aDeviceId, &ptr8));
		
	if (ret == KErrNone)
		{
		const TUint* recvedIds = reinterpret_cast<const TUint*>(buf->Ptr());
		if (!recvedIds)
			{
			delete buf;
			return KErrCorrupt;
			}
			
		TInt arraySize = *recvedIds++;
		// Copy received language ids to aLangIds
		for (TInt i = 0; i < arraySize; i++)
			{
			ret = aLangIds.Append(*recvedIds++); // increments by sizeof(TUint)
			if ( ret )
				{
				aLangIds.Reset();
				break;
				}
			}
		}
		
	delete buf;	
	return ret;
	}
	
EXPORT_C TInt RUsb::GetManufacturerStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString)
	{
	LOG_LINE
	LOG_FUNC

	return SendReceive(EUsbGetManufacturerStringDescriptor, TIpcArgs(aDeviceId, aLangId, &aString));
	}

EXPORT_C TInt RUsb::GetProductStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString)
	{
	LOG_LINE
	LOG_FUNC

	return SendReceive(EUsbGetProductStringDescriptor, TIpcArgs(aDeviceId, aLangId, &aString));
	}

EXPORT_C TInt RUsb::GetOtgDescriptor(TUint aDeviceId, TOtgDescriptor& aDescriptor)
	{
	LOG_LINE
	LOG_FUNC
		
	TPckg<TOtgDescriptor> otgDescPkg(aDescriptor);
	
	TIpcArgs args;
	args.Set(0, aDeviceId);
	args.Set(1, &otgDescPkg);

	return SendReceive(EUsbGetOtgDescriptor, args);
	}


EXPORT_C TInt RUsb::RequestSession()
	{
	LOG_LINE
	LOG_FUNC

	return SendReceive(EUsbRequestSession);
	}

EXPORT_C TInt RUsb::GetDetailedDescription(TInt aPersonalityId, HBufC*& aLocalizedPersonalityDescriptor)
	{
	LOG_LINE
	LOG_FUNC

 	TInt ret = KErrNone;
	// caller is responsible for freeing up memory allocated for aLocalizedPersonalityDescriptor
	TRAP(ret, aLocalizedPersonalityDescriptor = HBufC::NewL(KUsbStringDescStringMaxSize));
	if (ret == KErrNone)
		{
		TPtr ptr = aLocalizedPersonalityDescriptor->Des();
		TIpcArgs ipcArgs(0, &ptr);
		ipcArgs.Set(0, aPersonalityId);
		ret = SendReceive(EUsbGetDetailedDescription, ipcArgs);
		}
	else
		{
		// just in case caller tries to free the memory before checking the return code
		aLocalizedPersonalityDescriptor = NULL;
		}

	return ret; 
	}

EXPORT_C TInt RUsb::GetPersonalityProperty(TInt aPersonalityId, TUint32& aProperty)
	{
	LOG_LINE
	LOG_FUNC

    CUsbLog::Write(KLogStub, KNullDesC8());
	TPckg<TUint32> pkg(aProperty);
	TInt ret = SendReceive(EUsbGetPersonalityProperty, TIpcArgs(aPersonalityId, &pkg));
	if (ret == KErrNone)
		{
		aProperty = static_cast<TUint32>(pkg());
		}

//    CUsbLog::Write(KLogStub, KNullDesC8());
//    CStubber* stubber = CStubber::NewL();
//    TApiBehavior beh( KUsbManStubAgentDll, EGetPersonalityProperty, 0, 0, KNullDesC8 );
//    stubber -> InvokeApi( beh );
//    
//    delete stubber;
//    stubber = NULL;
//
//    if ( beh.iOutput != KNullDesC8 )
//        {
//        if ( !beh.iOutput.Compare( _L8( "stub" ) ) )
//            {
//            CUsbLog::Write(KLogStub, KNullDesC8());
//            TRequestStatus stat;
//            TInt message;
//            MessageNotification(stat,message);
//            DeviceStateNotificationCancel();
//            TUsbDeviceState aState;
//            GetDeviceState(aState);
//            DeviceStateNotification( KUsbAllStates, aState, stat );
//            TryStop(stat);
//            User::WaitForRequest(stat);
//            TInt personalityId;
//            GetCurrentPersonalityId(personalityId);
//            TryStart(personalityId,stat);
//            User::WaitForRequest(stat);
//            }
//        else
//            {}
//        }
    
	return ret;	
	}