// 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 the License "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 <e32cmn.h>
#include <e32cmn_private.h>
#include <e32property.h>
#include <d32otgdi.h>
#include "..\..\t_usbdi\inc\testdebug.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "t_usbhost_usbmanTraces.h"
#endif

_LIT(KOtgdiLddFileName, "otgdi");
_LIT(KArgClient,        "client");

static const TUid KWordOfDeathCat = {0x01066600};
static const TInt KWordOfDeathKey = 0x01066601;

TBool RunClient(RUsbOtgDriver& aOtg, TInt event);
TBool RunHost(RUsbOtgDriver& aOtg, TInt event);

TInt E32Main()
	{
	OstTrace0(TRACE_NORMAL, E32MAIN_E32MAIN, "---> Main OTG Sub-Process");

	CTrapCleanup* trapHandler = CTrapCleanup::New();

	if(!trapHandler)
		{
		return KErrNoMemory;
		}

	TBool clientFlag = EFalse; // default to host
	
	// Process the command line option for role
	TInt cmdLineLength(User::CommandLineLength());

	if(cmdLineLength != 0)
		{
		HBufC* cmdLine = HBufC::NewMax(cmdLineLength);	
		TPtr cmdLinePtr = cmdLine->Des();
		User::CommandLine(cmdLinePtr);
		TLex args(*cmdLine);
		args.SkipSpace();
		
		// Obtain the role of this test module
		TPtrC firstToken = args.NextToken(); // e.g. client ??

		if(firstToken.Compare(KArgClient) == 0)
			{
			clientFlag = ETrue;
            OstTrace0(TRACE_NORMAL, E32MAIN_E32MAIN_DUP01, "usbhost_usbman running as a Client");
			}
		else
			{
			clientFlag = EFalse;
            OstTrace0(TRACE_NORMAL, E32MAIN_E32MAIN_DUP02, "usbhost_usbman running as a Host");
			}

		delete cmdLine;
		}			

	TInt r = User::LoadLogicalDevice(KOtgdiLddFileName);

	if(r != KErrNone && r != KErrAlreadyExists) // persistent loading since process will be killed while it is in the loop below and doesnt unload it
		{
		OstTrace1(TRACE_NORMAL, E32MAIN_E32MAIN_DUP03, "   LoadLogicalDevice(KOtgdiLddFileName) error = %d", r);
		delete trapHandler;
		return r;		
		}

	
	RUsbOtgDriver otg;
	RProperty wordofdeath;
	TRequestStatus waiting_for_death;
	TRequestStatus status;
	RUsbOtgDriver::TOtgEvent event;
	TBool running = ETrue;
	
	OstTrace0(TRACE_NORMAL, E32MAIN_E32MAIN_DUP04, "   opening otg driver");
	
	r = otg.Open();
	if(r != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, E32MAIN_E32MAIN_DUP05, "   otg.Open fails %d", r);
        goto Abort;
		}

	OstTrace0(TRACE_NORMAL, E32MAIN_E32MAIN_DUP06, "   otg driver successfully opened");

	OstTrace0(TRACE_NORMAL, E32MAIN_E32MAIN_DUP07, "   otg : starting stacks now");
	
	r = otg.StartStacks();

	if(r != KErrNone)
		{
		OstTrace1(TRACE_NORMAL, E32MAIN_E32MAIN_DUP08, "   otg.StartStacks fails %d", r);
        goto Abort;
		}	

	OstTrace0(TRACE_NORMAL, E32MAIN_E32MAIN_DUP09, "   otg stacks successfully started");

//	RProcess::Rendezvous(KErrNone);

    // attach to the word of deathproperty
    r = wordofdeath.Attach(KWordOfDeathCat, KWordOfDeathKey, EOwnerThread);
    if(r != KErrNone)
        {
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS, "Failed to connect to word of death");
        }
    
    // wait for the previously attached counterproperty to be updated
    wordofdeath.Subscribe(waiting_for_death);
    while(running)
        {
		otg.QueueOtgEventRequest(event, status);
		User::WaitForRequest(status, waiting_for_death);

        OstTrace1(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP01, "waiting_for_death= %d", waiting_for_death.Int());
        OstTrace1(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP02, "Otg Event        = %d", status.Int());

        r = waiting_for_death.Int();
        if(r != KRequestPending)
            {
            running = EFalse;
            continue;
            }

        r = status.Int();
        if(r != KRequestPending)
            {
            // Run client or host modes against this otg event
            if(clientFlag)
                {		
                running = RunClient(otg, event);
                }
            else
                {
                running = RunHost(otg, event);
                }
            }
        }

	// Shut down nicely

    OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP03, "StopStacks()");

    otg.StopStacks(); //NB This drops the bus

    OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP04, "******** ShutdownStack Complete ********");

    OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP05, "Close Otg stack()");

    otg.Close();

Abort:
    OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP06, "Free LDD");
    User::FreeLogicalDevice(RUsbOtgDriver::Name());

    delete trapHandler;

    OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP07, "usbhost_usbman Finished");

    return KErrNone;
    }
	



TBool RunClient(RUsbOtgDriver& aOtg, TInt event)
    {
    switch(event)
        {
    case RUsbOtgDriver::EEventVbusRaised:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP08, "Client Side : Vbus raise detected due to Event VbusRaised");
        break;

    case RUsbOtgDriver::EEventRoleChangedToDevice:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP09, "Client Side : Vbus raise detected due to Event RoleChangedToDevice");
        break;

    default:
        OstTrace1(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP10, "Client Side : Event %d received", event);
        break;
        }

    return ETrue;
    }




TBool RunHost(RUsbOtgDriver& aOtg, TInt event)
    {
    TInt r;
    switch(event)
        {
    case RUsbOtgDriver::EEventAPlugInserted:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP11, "Host side otg got APlugInserted Event");
        r = aOtg.BusRequest();
        OstTrace1(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP12, "BusRequest() made - returned %d", r);
        break;

    case RUsbOtgDriver::EEventAPlugRemoved:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP13, "Host side otg got APlugRemoved Event - shutting down");
        return EFalse;

    case RUsbOtgDriver::EEventVbusRaised:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP14, "Host side otg got VbusRaised Event");
        break;

    case RUsbOtgDriver::EEventVbusDropped:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP15, "Host side otg got VbusDropped Event");
        break;

    case RUsbOtgDriver::EEventSrpInitiated:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP16, "Host side otg got SrpInitiated Event");
        break;

    case RUsbOtgDriver::EEventSrpReceived:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP17, "Host side otg got SrpReceived Event");
        break;

    case RUsbOtgDriver::EEventHnpEnabled:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP18, "Host side otg got HnpEnabled Event");
        break;

    case RUsbOtgDriver::EEventHnpDisabled:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP19, "Host side otg got HnpDisabled Event");
        break;

    case RUsbOtgDriver::EEventHnpSupported:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP20, "Host side otg got HnpSupported Event");
        break;

    case RUsbOtgDriver::EEventHnpAltSupported:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP21, "Host side otg got HnpAltSupported Event");
        break;


    case RUsbOtgDriver::EEventBusConnectionBusy:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP22, "Host side otg got BusConnectionBusy Event");
        break;

    case RUsbOtgDriver::EEventBusConnectionIdle:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP23, "Host side otg got BusConnectionIdle Event");
        break;


    case RUsbOtgDriver::EEventRoleChangedToHost:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP24, "Host side otg got RoleChangedToHost Event");
        break;

    case RUsbOtgDriver::EEventRoleChangedToDevice:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP25, "Host side otg got RoleChangedToDevice Event");
        break;

    case RUsbOtgDriver::EEventRoleChangedToIdle:
        OstTrace0(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP26, "Host side otg got RoleChangedToIdle Event");
        break;

    default:
        OstTrace1(TRACE_NORMAL, RPROCESS_RENDEZVOUS_DUP27, "Host Side otg unknown event catcher tickled - event %d - shutting down", event);
        return EFalse;
     }

    return ETrue;
    }

