usbdrv/peripheral/ldd/perildd/src/d_usbc.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 17 Sep 2010 08:40:15 +0300
changeset 51 eaaed528d5fd
parent 36 1a2a19ee918d
child 59 bbdce6bffaad
permissions -rw-r--r--
Revision: 201037 Kit: 201037

// Copyright (c) 2000-2009 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:
// e32/drivers/usbc/d_usbc.cpp
// LDD for USB Device driver stack:
// The channel object.
// 
//

/**
 @file d_usbc.cpp
 @internalTechnology
*/

#include <usb/usbc.h>


_LIT(KUsbLddName, "Usbc");

static const TInt KUsbRequestCallbackPriority = 2;


// Quick sanity check on endpoint properties
static TBool ValidateEndpoint(const TUsbcEndpointInfo* aEndpointInfo)
    {
    const TUint dir = aEndpointInfo->iDir;
    const TInt size = aEndpointInfo->iSize;
    if (size <= 0)
        return EFalse;

    switch (aEndpointInfo->iType)
        {
    case UsbShai::KUsbEpTypeControl:
        if (dir != UsbShai::KUsbEpDirBidirect || size > 64)
            return EFalse;
        break;
    case UsbShai::KUsbEpTypeIsochronous:
        if ((dir != UsbShai::KUsbEpDirIn && dir != UsbShai::KUsbEpDirOut) || size > 1024)
            return EFalse;
        break;
    case UsbShai::KUsbEpTypeBulk:
        if ((dir != UsbShai::KUsbEpDirIn && dir != UsbShai::KUsbEpDirOut) || size > 512)
            return EFalse;
        break;
    case UsbShai::KUsbEpTypeInterrupt:
        if ((dir != UsbShai::KUsbEpDirIn && dir != UsbShai::KUsbEpDirOut) || size > 1024)
            return EFalse;
        break;
    default:
        return EFalse;
        }
    return ETrue;
    }


/** Real entry point from the Kernel: return a new driver.
 */
DECLARE_STANDARD_LDD()
    {
    return new DUsbcLogDevice;
    }


/** Create a channel on the device.

    @internalComponent
*/
TInt DUsbcLogDevice::Create(DLogicalChannelBase*& aChannel)
    {
    aChannel = new DLddUsbcChannel;
    return aChannel ? KErrNone : KErrNoMemory;
    }


DUsbcLogDevice::DUsbcLogDevice()
      {
      iParseMask = KDeviceAllowUnit;
      iUnitsMask = 0xffffffff;                                // Leave units decision to the Controller
      iVersion = TVersion(KUsbcMajorVersion, KUsbcMinorVersion, KUsbcBuildVersion);
      }


TInt DUsbcLogDevice::Install()
    {
    // Only proceed if we have the Controller underneath us
    if (!DUsbClientController::UsbcControllerPointer())
        {
        __KTRACE_OPT(KPANIC, Kern::Printf("LDD Install: USB Controller Not Present"));
        return KErrGeneral;
        }
    return SetName(&KUsbLddName);
    }


//
// Return the USB controller capabilities.
//
void DUsbcLogDevice::GetCaps(TDes8& aDes) const
    {
    TPckgBuf<TCapsDevUsbc> b;
    b().version = iVersion;
    Kern::InfoCopy(aDes, b);
    }


//
// Constructor
//
DLddUsbcChannel::DLddUsbcChannel()
    : iValidInterface(EFalse),
      iAlternateSettingList(NULL),
      iCompleteAllCallbackInfo(this, DLddUsbcChannel::EmergencyCompleteDfc, KUsbRequestCallbackPriority),
      iStatusChangePtr(NULL),
      iStatusCallbackInfo(this, DLddUsbcChannel::StatusChangeCallback, KUsbRequestCallbackPriority),
      iEndpointStatusChangePtr(NULL),
      iEndpointStatusCallbackInfo(this, DLddUsbcChannel::EndpointStatusChangeCallback,
                                  KUsbRequestCallbackPriority),
      iOtgFeatureChangePtr(NULL),
      iOtgFeatureCallbackInfo(this, DLddUsbcChannel::OtgFeatureChangeCallback, KUsbRequestCallbackPriority),
      iChargerTypeChangePtr(NULL),
      iChargerTypeCallbackInfo(this, DLddUsbcChannel::ChargerTypeChangeCallback, KUsbRequestCallbackPriority),
      iNumberOfEndpoints(0),
      iDeviceState(UsbShai::EUsbPeripheralStateUndefined),
      iOwnsDeviceControl(EFalse),
      iAlternateSetting(0),
      iDeviceStatusNeeded(EFalse),
      iChannelClosing(EFalse)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("*** DLddUsbcChannel::DLddUsbcChannel CTOR"));
    iClient = &Kern::CurrentThread();
    iClient->Open();
    for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
        {
        iEndpoint[i] = NULL;
        }
    for (TInt i = 1; i < KUsbcMaxRequests; i++)
        {
        iRequestStatus[i] = NULL;
        }
    }


DLddUsbcChannel::~DLddUsbcChannel()
    {
    __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::~DLddUsbcChannel()"));
    if (iController)
        {
        iController->DeRegisterClient(this);
        iStatusCallbackInfo.Cancel();
        iEndpointStatusCallbackInfo.Cancel();
        iOtgFeatureCallbackInfo.Cancel();
        iChargerTypeCallbackInfo.Cancel();
        iCompleteAllCallbackInfo.Cancel();
        AbortInterface();
        DestroyAllInterfaces();
        if (iOwnsDeviceControl)
            {
            iController->ReleaseDeviceControl(this);
            iOwnsDeviceControl = EFalse;
            }
        DestroyEp0();
        delete iStatusFifo;
        Kern::DestroyClientRequest(iStatusChangeReq);
        Kern::DestroyClientRequest(iEndpointStatusChangeReq);
        Kern::DestroyClientRequest(iOtgFeatureChangeReq);
        Kern::DestroyClientRequest(iChargerTypeChangeReq);
        Kern::DestroyVirtualPinObject(iPinObj1);
        Kern::DestroyVirtualPinObject(iPinObj2);
        Kern::DestroyVirtualPinObject(iPinObj3);

        for (TInt i = 0; i < KUsbcMaxRequests; i++)
            {
            Kern::DestroyClientBufferRequest(iClientAsynchNotify[i]->iBufferRequest);
            delete iClientAsynchNotify[i];
            }
        }
    Kern::SafeClose((DObject*&)iClient, NULL);
    }


inline TBool DLddUsbcChannel::ValidEndpoint(TInt aEndpoint)
    {
    return (aEndpoint <= iNumberOfEndpoints && aEndpoint >= 0);
    }


//
// Create channel
//
TInt DLddUsbcChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("LDD DoCreateL 1 Ver = %02d %02d %02d",
                                    aVer.iMajor, aVer.iMinor, aVer.iBuild));
    if (!Kern::CurrentThreadHasCapability(ECapabilityCommDD,
                                          __PLATSEC_DIAGNOSTIC_STRING("Checked by USBC.LDD (USB Driver)")))
        {
        return KErrPermissionDenied;
        }

    iController = DUsbClientController::UsbcControllerPointer();

    if (!iController)
        {
        return KErrGeneral;
        }

    iStatusFifo = new TUsbcDeviceStatusQueue;
    if (iStatusFifo == NULL)
        {
        return KErrNoMemory;
        }

      if (!Kern::QueryVersionSupported(TVersion(KUsbcMajorVersion, KUsbcMinorVersion, KUsbcBuildVersion), aVer))
        {
        return KErrNotSupported;
        }

    // set up the correct DFC queue
    SetDfcQ(iController->DfcQ(0));                            // sets the channel's dfc queue
    #ifdef DFC_REALTIME_STATE
        iDfcQ.SetRealtimeState(ERealtimeStateOn);
    #endif
    iCompleteAllCallbackInfo.SetDfcQ(iDfcQ);
    iStatusCallbackInfo.SetDfcQ(iDfcQ);                        // use the channel's dfcq for this dfc
    iEndpointStatusCallbackInfo.SetDfcQ(iDfcQ);                // use the channel's dfcq for this dfc
    iOtgFeatureCallbackInfo.SetDfcQ(iDfcQ);
    iChargerTypeCallbackInfo.SetDfcQ(iDfcQ);
	iMsgQ.Receive();										//start up the message q
	TInt r = iController->RegisterClientCallback(iCompleteAllCallbackInfo);
	if (r != KErrNone)
		return r;
	r = iController->RegisterForStatusChange(iStatusCallbackInfo);
	if (r != KErrNone)
		return r;
	r = iController->RegisterForEndpointStatusChange(iEndpointStatusCallbackInfo);
	if (r != KErrNone)
		return r;
	r = iController->RegisterForOtgFeatureChange(iOtgFeatureCallbackInfo);
	if (r != KErrNone)
		return r;	
    r = iController->RegisterChargingPortTypeNotify(iChargerTypeCallbackInfo);
    if (r != KErrNone)
        return r;	
	
	r = Kern::CreateClientDataRequest(iStatusChangeReq);
	if (r != KErrNone)
		return r;
	r = Kern::CreateClientDataRequest(iEndpointStatusChangeReq);
	if (r != KErrNone)
		return r;
	r = Kern::CreateClientDataRequest(iOtgFeatureChangeReq);
	if (r != KErrNone)
		return r;
    r = Kern::CreateClientDataRequest(iChargerTypeChangeReq);
    if (r != KErrNone)
        return r;	
    
    Kern::CreateVirtualPinObject(iPinObj1);
    Kern::CreateVirtualPinObject(iPinObj2);
    Kern::CreateVirtualPinObject(iPinObj3);

    for (TInt i = 0; i < KUsbcMaxRequests; i++)
        {
            iClientAsynchNotify[i] = new TClientAsynchNotify;
            if(iClientAsynchNotify[i] == NULL)
                return KErrNoMemory;
            r = Kern::CreateClientBufferRequest(iClientAsynchNotify[i]->iBufferRequest,1,TClientBufferRequest::EPinVirtual);
            if (r != KErrNone)
                {
                delete iClientAsynchNotify[i];
                iClientAsynchNotify[i]=NULL;
                return r;
                }
        }
    
    return r;
    }



void DLddUsbcChannel::CompleteBufferRequest(DThread* aThread, TInt aReqNo, TInt aReason)
{
    iRequestStatus[aReqNo]=NULL;
    Kern::QueueBufferRequestComplete(aThread, iClientAsynchNotify[aReqNo]->iBufferRequest, aReason);
}


TClientBuffer * DLddUsbcChannel::GetClientBuffer(TInt aEndpoint)
{
    return iClientAsynchNotify[aEndpoint]->iClientBuffer;
}

//Runs in client thread
TInt DLddUsbcChannel::SendMsg(TMessageBase * aMsg)
{
    TThreadMessage& m=* (TThreadMessage*)aMsg;
    TInt id = m.iValue;
    
    TInt r = KErrNone;
    //Cancel Request
    if (id == KMaxTInt)
        {
            r = DLogicalChannel::SendMsg(aMsg);
            return r;
        }
    if (id < 0)
        {
        // DoRequest
        TRequestStatus* pS = (TRequestStatus*) m.Ptr0();
        r = PreSendRequest(aMsg,~id, pS, m.Ptr1(), m.Ptr2());
        if (r == KErrNone)
            {
            r = DLogicalChannel::SendMsg(aMsg);
            }
        }
    else
        {
        //SendControl
        r = SendControl(aMsg);
        }
    return r;
}


TInt DLddUsbcChannel::PreSendRequest(TMessageBase * aMsg,TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
{
    TInt r = KErrNone;
    if (aReqNo >= KUsbcMaxRequests)
    {
        Kern::RequestComplete(aStatus, KErrNotSupported);
        return KErrNotSupported;
    }
    if (aReqNo > KUsbcMaxEpNumber)//DoOtherAsyncReq
    {
        switch (aReqNo)
        {
            case RDevUsbcClient::ERequestEndpointStatusNotify:
                iEndpointStatusChangeReq->Reset();
                iEndpointStatusChangeReq->SetStatus(aStatus);
                iEndpointStatusChangeReq->SetDestPtr(a1);
            break;
            case RDevUsbcClient::ERequestOtgFeaturesNotify:
                iOtgFeatureChangeReq->Reset();
                iOtgFeatureChangeReq->SetStatus(aStatus);
                iOtgFeatureChangeReq->SetDestPtr(a1);
            break;
            case RDevUsbcClient::ERequestChargingPortTypeNotify:
                iChargerTypeChangeReq->Reset();
                iChargerTypeChangeReq->SetStatus(aStatus);
                iChargerTypeChangeReq->SetDestPtr(a1);
            break;	
            case RDevUsbcClient::ERequestAlternateDeviceStatusNotify:
                iStatusChangeReq->Reset();
                iStatusChangeReq->SetStatus(aStatus);
                iStatusChangeReq->SetDestPtr(a1);
            break;
            case RDevUsbcClient::ERequestReEnumerate://WE use bufferrequest to complete even tho we dont add any buffers
                iClientAsynchNotify[aReqNo]->Reset();
                r=iClientAsynchNotify[aReqNo]->iBufferRequest->StartSetup(aStatus);
                if (r != KErrNone)
                    return r;
                iClientAsynchNotify[aReqNo]->iBufferRequest->EndSetup();
            break;
        }
    }
    else //DoTransferAsyncReq
    {
            if(a1 == NULL)
                return KErrArgument;
            iClientAsynchNotify[aReqNo]->Reset();
            r=iClientAsynchNotify[aReqNo]->iBufferRequest->StartSetup(aStatus);
            if (r != KErrNone)
                return r;
            kumemget(&iTfrInfo,a1,sizeof(TEndpointTransferInfo));
            r=iClientAsynchNotify[aReqNo]->iBufferRequest->AddBuffer(iClientAsynchNotify[aReqNo]->iClientBuffer, iTfrInfo.iDes);
            if (r != KErrNone)
                return r;
            iClientAsynchNotify[aReqNo]->iBufferRequest->EndSetup();
            TThreadMessage& m=*(TThreadMessage*)aMsg;
            m.iArg[1] = (TAny*)&iTfrInfo; //Use Channel owned TransfereInfo structure 
    }
    return KErrNone;
}


void DLddUsbcChannel::HandleMsg(TMessageBase* aMsg)
    {
    TThreadMessage& m = *(TThreadMessage*)aMsg;
    TInt id = m.iValue;
    if (id == (TInt) ECloseMsg)
        {
        iChannelClosing = ETrue;
        m.Complete(KErrNone, EFalse);
        return;
        }
    else if (id == KMaxTInt)
        {
        // Cancel request
        TInt mask = m.Int0();
        TInt b = 1;
        for(TInt reqNo = 0; reqNo < KUsbcMaxRequests; reqNo++)
            {
            TRequestStatus* pS = iRequestStatus[reqNo];
            if ((mask & b) && (pS != NULL))
                {
                DoCancel(reqNo);
                }
            b <<= 1;
            }
        m.Complete(KErrNone, ETrue);
        return;
        }

    if (id < 0)
        {
        // DoRequest
        TRequestStatus* pS = (TRequestStatus*) m.Ptr0();
        DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
        m.Complete(KErrNone, ETrue);
        }
    else
        {
        // DoControl
        TInt r = DoControl(id, m.Ptr0(), m.Ptr1());
        m.Complete(r, ETrue);
        }
    }


//
// Overriding DObject virtual
//
TInt DLddUsbcChannel::RequestUserHandle(DThread* aThread, TOwnerType /*aType*/)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::RequestUserHandle"));
    // The USB client LDD is not designed for a channel to be shared between
    // threads. It saves a pointer to the current thread when it is opened, and
    // uses this to complete any asynchronous requests.
    // It is therefore not acceptable for the handle to be duplicated and used
    // by another thread:
    if (aThread == iClient)
        {
        return KErrNone;
        }
    else
        {
        return KErrAccessDenied;
        }
    }


//
// Asynchronous requests - overriding pure virtual
//
void DLddUsbcChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
    {
    // Check on request status
    __KTRACE_OPT(KUSB, Kern::Printf("DoRequest 0x%08x", aReqNo));
        TInt r = KErrNone;
        if (iRequestStatus[aReqNo] != NULL)
            {
            DestroyAllInterfaces();
            PanicClientThread(ERequestAlreadyPending);
            }
        else
            {
            TBool needsCompletion;
            iRequestStatus[aReqNo] = aStatus;

            if (aReqNo > KUsbcMaxEpNumber)
                {
                r = DoOtherAsyncReq(aReqNo, a1, a2, needsCompletion);
                if (needsCompletion)
                    {
                    switch (aReqNo)
                    {
                        case RDevUsbcClient::ERequestEndpointStatusNotify:
                            iRequestStatus[aReqNo]=NULL;
                            Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,r);
                        break;
                        case RDevUsbcClient::ERequestOtgFeaturesNotify:
                            iRequestStatus[aReqNo]=NULL;
                            Kern::QueueRequestComplete(iClient,iOtgFeatureChangeReq,r);
                        break;
                        case RDevUsbcClient::ERequestChargingPortTypeNotify:
                            iRequestStatus[aReqNo]=NULL;
                            Kern::QueueRequestComplete(iClient,iChargerTypeChangeReq,r);
                        break;
                        case RDevUsbcClient::ERequestAlternateDeviceStatusNotify:
                            iRequestStatus[aReqNo]=NULL;
                            Kern::QueueRequestComplete(iClient,iStatusChangeReq,r);
                        break;
                        case RDevUsbcClient::ERequestReEnumerate:
                            iRequestStatus[aReqNo]=NULL;
                            Kern::QueueBufferRequestComplete(iClient, iClientAsynchNotify[aReqNo]->iBufferRequest, r);
                        break;
                    }
                  }
                }
            else
                {
                r = DoTransferAsyncReq(aReqNo, a1, a2, needsCompletion);
                if (needsCompletion)
                    {
                    //Kern::RequestComplete(iClient, iRequestStatus[aReqNo], r);
                    CompleteBufferRequest(iClient, aReqNo, r);
                    }
                }
            }
    }



TInt DLddUsbcChannel::DoOtherAsyncReq(TInt aReqNo, TAny* a1, TAny* a2, TBool& aNeedsCompletion)
    {
    // The general assumption is that none of these will complete now.
    // However, those that make this function return something other than
    // KErrNone will get completed by the calling function.
    // So, 1) If you are returning KErrNone but really need to complete because
    //        completion criteria can be met (for example, sufficient data is
    //        available in the buffer) and then set aNeedsCompletion = ETrue.
    //     2) Do NOT complete here AT ALL.
    //
    aNeedsCompletion = EFalse;
    TInt r = KErrNone;

    switch (aReqNo)
        {
    case RDevUsbcClient::ERequestAlternateDeviceStatusNotify:
        {
        __KTRACE_OPT(KUSB, Kern::Printf("EControlReqDeviceStatusNotify"));
        if (a1 != NULL)
            {
            iDeviceStatusNeeded = ETrue;
            iStatusChangePtr = a1;
            aNeedsCompletion = AlternateDeviceStateTestComplete();
            }
        else
            r = KErrArgument;
        break;
        }
    case RDevUsbcClient::ERequestReEnumerate:
        {
        __KTRACE_OPT(KUSB, Kern::Printf("ERequestReEnumerate"));
        // If successful, this will complete via the status notification.
        r = iController->ReEnumerate();
        break;
        }
    case RDevUsbcClient::ERequestEndpointStatusNotify:
        {
        __KTRACE_OPT(KUSB, Kern::Printf("ERequestEndpointStatusNotify"));
        if (a1 != NULL)
            {
            iEndpointStatusChangePtr = a1;
            }
        else
            r = KErrArgument;
        break;
            }
    case RDevUsbcClient::ERequestOtgFeaturesNotify:
        {
        __KTRACE_OPT(KUSB, Kern::Printf("ERequestOtgFeaturesNotify"));
        if (a1 != NULL)
            {
            iOtgFeatureChangePtr = a1;
            }
        else
            r = KErrArgument;
        break;
        }
    case RDevUsbcClient::ERequestChargingPortTypeNotify:
        {
        __KTRACE_OPT(KUSB, Kern::Printf("ERequestChargingPortTypeNotify"));
        if (a1 != NULL)
            {
            iChargerTypeChangePtr = a1;         
            aNeedsCompletion = iChargerTypeCallbackInfo.PendingNotify();
            if(aNeedsCompletion)
                {
                iChargerTypeChangeReq->Data()= iChargerTypeCallbackInfo.ChargerType();
                iChargerTypeChangePtr = NULL;
                iChargerTypeCallbackInfo.SetPendingNotify(EFalse);
                }
            }
        else
            r = KErrArgument;
        break;
        }
    default:
        r = KErrNotSupported;
        }

    aNeedsCompletion = aNeedsCompletion || (r != KErrNone);

    return r;
    }


TInt DLddUsbcChannel::DoTransferAsyncReq(TInt aEndpointNum, TAny* a1, TAny* a2, TBool& aNeedsCompletion)
    {
    // The general assumption is that none of these will complete now.
    // however, those that are returning something other than KErrNone will get completed
    // by the calling function.
    // So,    1) if you are returning KErrNone but really need to complete because completion criteria can be met
    //            (for example, sufficient data is available in the buffer) and then set aNeedsCompletion=ETrue..
    //        2) Do NOT complete here AT ALL.
    //
    aNeedsCompletion = EFalse;
    TInt r = KErrNone;
    TUsbcEndpoint* pEndpoint = NULL;
    TUsbcEndpointInfo* pEndpointInfo = NULL;
    TEndpointTransferInfo* pTfr = NULL;

    if (aEndpointNum == 0)
        {
        // ep0 requests
        if (!(iValidInterface || iOwnsDeviceControl))
            {
            __KTRACE_OPT(KUSB, Kern::Printf("DoRequest rejected: not configured (Ep0)"));
            r = KErrUsbInterfaceNotReady;
            goto exit;
            }
        }
    else
        {
        // other eps
        if (!(iValidInterface && (iDeviceState == UsbShai::EUsbPeripheralStateConfigured ||
                                  iDeviceState == UsbShai::EUsbPeripheralStateSuspended))
           )
            {
            __KTRACE_OPT(KUSB, Kern::Printf("DoRequest rejected not configured (Ep %d)", aEndpointNum));
            r = KErrUsbInterfaceNotReady;
            goto exit;
            }
        }

    if (!ValidEndpoint(aEndpointNum))
        {
        __KTRACE_OPT(KPANIC, Kern::Printf("  Error: DoRequest Read: in error complete"));
        r = KErrUsbEpNotInInterface;
        goto exit;
         }

    if (a1 == NULL)
        {
        r = KErrArgument;
        goto exit;
        }
    pTfr = (TEndpointTransferInfo *)a1;

    if (pTfr->iTransferSize < 0)
        {
        r = KErrArgument;
        goto exit;
        }
    pEndpoint = iEndpoint[aEndpointNum];
    if (!pEndpoint)
        {
        __KTRACE_OPT(KPANIC, Kern::Printf("  Error: DoRequest Read: in error complete"));
        r = KErrUsbEpNotInInterface;
        goto exit;
        }

    pEndpointInfo = pEndpoint->EndpointInfo();
    __KTRACE_OPT(KUSB, Kern::Printf("DoRequest %d", aEndpointNum));

    switch (pTfr->iTransferType)
        {

    case ETransferTypeReadData:
    case ETransferTypeReadPacket:
    case ETransferTypeReadUntilShort:
    case ETransferTypeReadOneOrMore:
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read"));
        if (pEndpoint->iDmaBuffers->RxIsActive())
            {
            __KTRACE_OPT(KUSB, Kern::Printf("**** ReadReq ep%d RxActive", aEndpointNum));
            }
        else
            {
            __KTRACE_OPT(KUSB, Kern::Printf("**** ReadReq ep%d RxInActive", aEndpointNum));
            }

        if (pEndpointInfo->iDir != UsbShai::KUsbEpDirOut &&
            pEndpointInfo->iDir != UsbShai::KUsbEpDirBidirect)
            {
            // Trying to do the wrong thing
            __KTRACE_OPT(KPANIC, Kern::Printf("  Error: DoRequest Read: in error complete"));
            r = KErrUsbEpBadDirection;
            break;
            }
        // Set the length of data to zero now to catch all cases
        TPtrC8 pZeroDesc(NULL, 0);
        r=Kern::ThreadBufWrite(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer, pZeroDesc, 0, 0,iClient);
        if (r != KErrNone)
            PanicClientThread(r);
        pEndpoint->SetTransferInfo(pTfr);
        if (pEndpoint->iDmaBuffers->IsReaderEmpty())
            {
            pEndpoint->SetClientReadPending(ETrue);
            }
        else
            {
            if (pTfr->iTransferType == ETransferTypeReadPacket)
                {
                __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read packet: data available complete"));
                r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer);
                aNeedsCompletion = ETrue;
                break;
                }
            else if (pTfr->iTransferType == ETransferTypeReadData)
                {
                if (pTfr->iTransferSize <= pEndpoint->RxBytesAvailable())
                    {
                    __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete"));
                    r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer);
                    aNeedsCompletion = ETrue;
                    break;
                    }
                else
                    {
                    pEndpoint->SetClientReadPending(ETrue);
                    }
                }
            else if (pTfr->iTransferType == ETransferTypeReadOneOrMore)
                {
                if (pEndpoint->RxBytesAvailable() > 0)
                    {
                    __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete"));
                    r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer);
                    aNeedsCompletion = ETrue;
                    break;
                    }
                else
                    {
                    pEndpoint->SetClientReadPending(ETrue);
                    }
                }
            else if (pTfr->iTransferType == ETransferTypeReadUntilShort)
                {
                TInt nRx = pEndpoint->RxBytesAvailable();
                TInt maxPacketSize = pEndpoint->EndpointInfo()->iSize;
                if( (pTfr->iTransferSize <= nRx) ||
                    (nRx < maxPacketSize) ||
                    pEndpoint->iDmaBuffers->ShortPacketExists())
                    {
                    __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete"));
                    r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer);
                    aNeedsCompletion = ETrue;
                    }
                else
                    {
                    pEndpoint->SetClientReadPending(ETrue);
                    }
                }
            }
        r = pEndpoint->TryToStartRead(EFalse);
        if (r != KErrNone)
            {
            __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read: couldn't start read"));
            r = KErrNone;                                    // Reader full isn't a userside error;
            }
        break;
        }

    case ETransferTypeWrite:
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 1"));
        if (pEndpointInfo->iDir != UsbShai::KUsbEpDirIn &&
            pEndpointInfo->iDir != UsbShai::KUsbEpDirBidirect)
            {
            __KTRACE_OPT(KPANIC, Kern::Printf("  Error: DoRequest Write: wrong direction complete"));
            r = KErrUsbEpBadDirection;
            break;
            }
        __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 2"));


        TInt desLength=iClientAsynchNotify[aEndpointNum]->iClientBuffer->Length();
        
        if (desLength < pTfr->iTransferSize)
            {
            __KTRACE_OPT(KPANIC, Kern::Printf("  Error: DoRequest Write: user buffer too short"));
            r = KErrUsbTransferSize;
            break;
            }

        __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 3 length=%d maxlength=%d",
                                        pTfr->iTransferSize, desLength));
        // Zero length writes are acceptable
        pEndpoint->SetClientWritePending(ETrue);
        r = pEndpoint->TryToStartWrite(pTfr);
        if (r != KErrNone)
            {
            __KTRACE_OPT(KPANIC, Kern::Printf("  Error: DoRequest Write: couldn't start write"));
            pEndpoint->SetClientWritePending(EFalse);
            }
        break;
        }

    default:
        __KTRACE_OPT(KPANIC, Kern::Printf("  Error: DoTransferAsyncReq: pTfr->iTransferType = %d not supported",
                                          pTfr->iTransferType));
        r = KErrNotSupported;
        break;
        }
 exit:
    aNeedsCompletion = aNeedsCompletion || (r != KErrNone);
    return r;
    }


//
// Cancel an outstanding request - overriding pure virtual
//
TInt DLddUsbcChannel::DoCancel(TInt aReqNo)
    {
    TInt r = KErrNone;
    __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: 0x%x", aReqNo));
    if (aReqNo <= iNumberOfEndpoints)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoCancel endpoint: 0x%x", aReqNo));
        iEndpoint[aReqNo]->CancelTransfer(iClient,iClientAsynchNotify[aReqNo]->iClientBuffer);
        }
    else if (aReqNo == RDevUsbcClient::ERequestAlternateDeviceStatusNotify)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: ERequestAlternateDeviceStatusNotify 0x%x", aReqNo));
        iDeviceStatusNeeded = EFalse;
        iStatusFifo->FlushQueue();
        if (iStatusChangePtr)
            {
            iStatusChangeReq->Data()=iController->GetDeviceStatus();
            iStatusChangePtr = NULL;

            if (iStatusChangeReq->IsReady())
                {
                iRequestStatus[aReqNo] = NULL;
                Kern::QueueRequestComplete(iClient, iStatusChangeReq, KErrCancel);
                }
                return KErrNone;
            }
        }
    else if (aReqNo == RDevUsbcClient::ERequestReEnumerate)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestReEnumerate: 0x%x", aReqNo));
        }
    else if (aReqNo == RDevUsbcClient::ERequestEndpointStatusNotify)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestEndpointStatusNotify: 0x%x", aReqNo));
        CancelNotifyEndpointStatus();
        if (iEndpointStatusChangeReq->IsReady())
            {
            iRequestStatus[aReqNo] = NULL;
            Kern::QueueRequestComplete(iClient, iEndpointStatusChangeReq, KErrCancel);
            }
        return KErrNone;
        }
    else if (aReqNo == RDevUsbcClient::ERequestOtgFeaturesNotify)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestOtgFeaturesNotify: 0x%x", aReqNo));
        CancelNotifyOtgFeatures();
        if (iOtgFeatureChangeReq->IsReady())
            {
            iRequestStatus[aReqNo] = NULL;
            Kern::QueueRequestComplete(iClient, iOtgFeatureChangeReq, KErrCancel);
            }
        }
    else if (aReqNo == RDevUsbcClient::ERequestChargingPortTypeNotify)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestChargingPortTypeNotify: 0x%x", aReqNo));
        CancelNotifyChargerType();
        if (iChargerTypeChangeReq->IsReady())
            {
            iRequestStatus[aReqNo] = NULL;
            Kern::QueueRequestComplete(iClient, iChargerTypeChangeReq, KErrCancel);
            }
        }
    else
        {
        __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Unknown! 0x%x", aReqNo));
        }

        if (r == KErrNone)
            r = KErrCancel;

        CompleteBufferRequest(iClient, aReqNo, r);
    return r;
    }


void DLddUsbcChannel::CancelNotifyEndpointStatus()
    {
    if (iEndpointStatusChangePtr)
        {
        TUint epBitmap = 0;
        for (TInt i = 0; i <= iNumberOfEndpoints; i++)
            {
            TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber());
            TUint b;
            (v == EEndpointStateStalled) ? b = 1 : b = 0;
            epBitmap |= b << i;
            }
        iEndpointStatusChangeReq->Data()=epBitmap;
        iEndpointStatusChangePtr = NULL;
        }
    }


void DLddUsbcChannel::CancelNotifyOtgFeatures()
    {
    if (iOtgFeatureChangePtr)
        {
        TUint8 features;
        iController->GetCurrentOtgFeatures(features);
     iOtgFeatureChangeReq->Data()=features;
        iOtgFeatureChangePtr = NULL;
        }
    }

void DLddUsbcChannel::CancelNotifyChargerType()
    {
    if (iChargerTypeChangePtr)
        {
        TUint chargerType;
        chargerType = iChargerTypeCallbackInfo.ChargerType();
        iChargerTypeChangeReq->Data()=chargerType;
        iChargerTypeChangePtr = NULL;
        iChargerTypeCallbackInfo.SetPendingNotify(EFalse);
        }
    }

TInt DLddUsbcChannel::PinMemory(TDesC8 *aDes, TVirtualPinObject *aPinObj)
    {
    TInt r = KErrNone;
    TInt  len,mlen;
    
    const TUint8*p = Kern::KUDesInfo(*aDes, len,mlen);
    r=Kern::PinVirtualMemory(aPinObj, (TLinAddr) p, len);
    return r;
    }

//Called in Client thread context
TInt DLddUsbcChannel::SendControl(TMessageBase* aMsg)
    {
    TThreadMessage& m=*(TThreadMessage*)aMsg;
    const TInt fn=m.iValue;
    TAny *const a1=m.Ptr0();
    TAny *const a2=m.Ptr1();
    TInt  kern_param;
    TEndpointDescriptorInfo epi;
    TUsbcIfcInfo ifc;
    TCSDescriptorInfo desInfo;
    TInt r = KErrNone;

    switch (fn)
        {
        
    case RDevUsbcClient::EControlDeviceStatus:
    case RDevUsbcClient::EControlGetAlternateSetting:
        m.iArg[0] = &kern_param;              // update message to point to kernel-side buffer
        break;

    case RDevUsbcClient::EControlQueryReceiveBuffer:
    case RDevUsbcClient::EControlEndpointStatus:
        m.iArg[1] = &kern_param;              // update message to point to kernel-side buffer
        break;

    case RDevUsbcClient::EControlEndpointCaps:
    case RDevUsbcClient::EControlDeviceCaps:
    case RDevUsbcClient::EControlGetDeviceDescriptor:
    case RDevUsbcClient::EControlSetDeviceDescriptor:
    case RDevUsbcClient::EControlGetDeviceDescriptorSize:
    case RDevUsbcClient::EControlGetConfigurationDescriptor:
    case RDevUsbcClient::EControlGetConfigurationDescriptorSize:
    case RDevUsbcClient::EControlGetDeviceQualifierDescriptor:
    case RDevUsbcClient::EControlSetDeviceQualifierDescriptor:
    case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor:
    case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor:
    case RDevUsbcClient::EControlGetStringDescriptorLangId:
    case RDevUsbcClient::EControlGetManufacturerStringDescriptor:
    case RDevUsbcClient::EControlSetManufacturerStringDescriptor:
    case RDevUsbcClient::EControlGetProductStringDescriptor:
    case RDevUsbcClient::EControlSetProductStringDescriptor:
    case RDevUsbcClient::EControlGetSerialNumberStringDescriptor:    
    case RDevUsbcClient::EControlSetSerialNumberStringDescriptor:
    case RDevUsbcClient::EControlGetConfigurationStringDescriptor:
    case RDevUsbcClient::EControlSetConfigurationStringDescriptor:
    case RDevUsbcClient::EControlSetOtgDescriptor:
    case RDevUsbcClient::EControlGetOtgDescriptor:
    case RDevUsbcClient::EControlGetOtgFeatures:
    case RDevUsbcClient::EControlGetChargerDetectorCaps:
        r=PinMemory((TDesC8 *) a1, iPinObj1);
        if(r!=KErrNone)
            {
            PanicClientThread(r);
            return r;
            }
        break;

    case RDevUsbcClient::EControlGetInterfaceDescriptor:
    case RDevUsbcClient::EControlGetInterfaceDescriptorSize:
    case RDevUsbcClient::EControlSetInterfaceDescriptor:
    case RDevUsbcClient::EControlGetCSInterfaceDescriptor:
    case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize:
    case RDevUsbcClient::EControlGetStringDescriptor:
    case RDevUsbcClient::EControlSetStringDescriptor:
        r=PinMemory((TDesC8 *) a2, iPinObj1);
        if(r!=KErrNone)
            {
            PanicClientThread(r);
            return r;
            }
        break;

    case RDevUsbcClient::EControlGetEndpointDescriptor:
    case RDevUsbcClient::EControlGetEndpointDescriptorSize:
    case RDevUsbcClient::EControlSetEndpointDescriptor:
    case RDevUsbcClient::EControlGetCSEndpointDescriptor:
    case RDevUsbcClient::EControlGetCSEndpointDescriptorSize:
        if(a1!=NULL)
            {
            r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a1, sizeof(epi));
            if(r!=KErrNone)
                {
                PanicClientThread(r);
                return r;
                }
            kumemget(&epi, a1, sizeof(epi));
            r=PinMemory((TDesC8 *) epi.iArg, iPinObj2);
            if(r!=KErrNone)
                {
                Kern::UnpinVirtualMemory(iPinObj1);
                PanicClientThread(r);
                return r;
                }
            }
        break;

    case RDevUsbcClient::EControlSetInterface:
        if(a2!=NULL)
            {
            r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a2, sizeof(ifc));
            if(r!=KErrNone)
                {
                PanicClientThread(r);
                return r;
                }    
            kumemget(&ifc, a2, sizeof(ifc));                
            r=PinMemory((TDesC8 *) ifc.iInterfaceData, iPinObj2);
            if(r!=KErrNone)
                {
                Kern::UnpinVirtualMemory(iPinObj1);
                PanicClientThread(r);
                return r;
                }
            }
        break;

    case RDevUsbcClient::EControlSetCSInterfaceDescriptor:
    case RDevUsbcClient::EControlSetCSEndpointDescriptor:
        if(a1!=NULL)
            {
            r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a1, sizeof(desInfo));
            if(r!=KErrNone)
                {
                PanicClientThread(r);
                return r;
                }
            kumemget(&desInfo, a1, sizeof(desInfo));
            r=PinMemory((TDesC8 *) desInfo.iArg, iPinObj2);
            if(r!=KErrNone)
                {
                Kern::UnpinVirtualMemory(iPinObj1);
                PanicClientThread(r);
                return r;
                }
            }
        break;
    }


    //Send Message and wait for synchronous complete    
    r = DLogicalChannel::SendMsg(aMsg);
    
    
    
    switch (fn)
        {
    case RDevUsbcClient::EControlDeviceStatus:
    case RDevUsbcClient::EControlGetAlternateSetting:
        umemput32(a1, &kern_param, sizeof(kern_param));
        break;

    case RDevUsbcClient::EControlQueryReceiveBuffer:
    case RDevUsbcClient::EControlEndpointStatus:
        umemput32(a2, &kern_param, sizeof(kern_param));
        break;

    case RDevUsbcClient::EControlDeviceCaps:
    case RDevUsbcClient::EControlEndpointCaps:
    case RDevUsbcClient::EControlGetDeviceDescriptor:
    case RDevUsbcClient::EControlSetDeviceDescriptor:
    case RDevUsbcClient::EControlGetDeviceDescriptorSize:
    case RDevUsbcClient::EControlGetConfigurationDescriptor:
    case RDevUsbcClient::EControlGetConfigurationDescriptorSize:
    case RDevUsbcClient::EControlGetDeviceQualifierDescriptor:
    case RDevUsbcClient::EControlSetDeviceQualifierDescriptor:
    case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor:
    case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor:
    case RDevUsbcClient::EControlGetStringDescriptorLangId:
    case RDevUsbcClient::EControlGetManufacturerStringDescriptor:
    case RDevUsbcClient::EControlSetManufacturerStringDescriptor:
    case RDevUsbcClient::EControlGetProductStringDescriptor:
    case RDevUsbcClient::EControlSetProductStringDescriptor:
    case RDevUsbcClient::EControlGetSerialNumberStringDescriptor:    
    case RDevUsbcClient::EControlSetSerialNumberStringDescriptor:
    case RDevUsbcClient::EControlGetConfigurationStringDescriptor:
    case RDevUsbcClient::EControlSetConfigurationStringDescriptor:
    case RDevUsbcClient::EControlSetOtgDescriptor:
    case RDevUsbcClient::EControlGetOtgDescriptor:
    case RDevUsbcClient::EControlGetOtgFeatures:
    case RDevUsbcClient::EControlGetChargerDetectorCaps:		
        if(a1!=NULL)
            {
            Kern::UnpinVirtualMemory(iPinObj1);
            }
        break;

    case RDevUsbcClient::EControlGetInterfaceDescriptor:
    case RDevUsbcClient::EControlGetInterfaceDescriptorSize:
    case RDevUsbcClient::EControlSetInterfaceDescriptor:
    case RDevUsbcClient::EControlGetCSInterfaceDescriptor:
    case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize:
    case RDevUsbcClient::EControlGetStringDescriptor:
    case RDevUsbcClient::EControlSetStringDescriptor:
        if(a2!=NULL)
            {
            Kern::UnpinVirtualMemory(iPinObj1);
            }
        break;
    
    case RDevUsbcClient::EControlGetEndpointDescriptor:
    case RDevUsbcClient::EControlGetEndpointDescriptorSize:
    case RDevUsbcClient::EControlSetEndpointDescriptor:
    case RDevUsbcClient::EControlGetCSEndpointDescriptor:
    case RDevUsbcClient::EControlGetCSEndpointDescriptorSize:
    case RDevUsbcClient::EControlSetCSInterfaceDescriptor:
    case RDevUsbcClient::EControlSetCSEndpointDescriptor:
        if(a1!=NULL)
            {
            Kern::UnpinVirtualMemory(iPinObj1);
            Kern::UnpinVirtualMemory(iPinObj2);
            }
        break;

    case RDevUsbcClient::EControlSetInterface:
        if(a2!=NULL)
            {
            Kern::UnpinVirtualMemory(iPinObj1);
            Kern::UnpinVirtualMemory(iPinObj2);
            }
        break;
        }

    return r;
    }


TInt DLddUsbcChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("DoControl: %d", aFunction));

    TInt r = KErrNone;
    TInt ep;
    TUsbcEndpoint* pEndpoint;
    TPtrC8 pZeroDesc(NULL, 0);
    TEndpointDescriptorInfo epInfo;
    TUsbcIfcInfo ifcInfo;
    TCSDescriptorInfo desInfo;
    TUsbcEndpointResource epRes;
	TUsbcChargerDetectorProperties chargingPro;	
    TInt bandwidthPriority;

    switch (aFunction)
        {
    case RDevUsbcClient::EControlEndpointZeroRequestError:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroRequestError"));
        r = KErrNone;
        if (iOwnsDeviceControl || (iValidInterface && iDeviceState == UsbShai::EUsbPeripheralStateConfigured))
            {
            iController->Ep0Stall(this);
            }
        else
            {
            if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
                r = KErrUsbDeviceNotConfigured;
            else
                r = KErrUsbInterfaceNotReady;
            }
        break;

    case RDevUsbcClient::EControlGetAlternateSetting:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetAlternateSetting"));
        if (iValidInterface && iDeviceState == UsbShai::EUsbPeripheralStateConfigured)
            {
            r = iController->GetInterfaceNumber(this, *(TInt*)a1);
            }
        else
            {
            if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
                r = KErrUsbDeviceNotConfigured;
            else
                r = KErrUsbInterfaceNotReady;
            }
        break;

    case RDevUsbcClient::EControlDeviceStatus:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceStatus"));
        *(TInt*)a1 = iController->GetDeviceStatus();
        break;

    case RDevUsbcClient::EControlEndpointStatus:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointStatus"));
        if (iValidInterface && ValidEndpoint((TInt) a1))
            {
            pEndpoint = iEndpoint[(TInt)a1];
            if (pEndpoint == NULL)
                r = KErrNotSupported;
            else
                {
                *(TInt*)a2 = iController->GetEndpointStatus(this, iEndpoint[(TInt)a1]->RealEpNumber());
                }
            }
        else
            {
            if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
                r = KErrUsbDeviceNotConfigured;
            else
                r = KErrUsbInterfaceNotReady;
            }
        break;

    case RDevUsbcClient::EControlQueryReceiveBuffer:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlQueryReceiveBuffer"));
        if (iValidInterface && ValidEndpoint((TInt) a1))
            {
            pEndpoint=iEndpoint[(TInt) a1];
            if (pEndpoint == NULL)
                r = KErrNotSupported;
            else if (pEndpoint->EndpointInfo()->iDir != UsbShai::KUsbEpDirIn)
                {
                __KTRACE_OPT(KUSB, Kern::Printf("  bytes = %d", pEndpoint->RxBytesAvailable()));
                *(TInt*)a2 = pEndpoint->RxBytesAvailable();
                }
            }
        else
            {
            if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
                r = KErrUsbDeviceNotConfigured;
            else
                r = KErrUsbInterfaceNotReady;
            }
        break;

    case RDevUsbcClient::EControlEndpointCaps:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointCaps"));
        r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient);
        if (r != KErrNone)
            PanicClientThread(r);
        iController->EndpointCaps(this, *((TDes8*) a1));
        break;

    case RDevUsbcClient::EControlDeviceCaps:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceCaps"));
        r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient);
        if (r != KErrNone)
            PanicClientThread(r);
        iController->DeviceCaps(this, *((TDes8*) a1));
        break;

    case RDevUsbcClient::EControlSendEp0StatusPacket:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSendEp0StatusPacket"));
        iController->SendEp0StatusPacket(this);
        break;

    case RDevUsbcClient::EControlHaltEndpoint:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlHaltEndpoint"));
        if (iValidInterface && ValidEndpoint((TInt) a1))
            {
            r = iController->HaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber());
            }
        else
            {
            if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
                r = KErrUsbDeviceNotConfigured;
            else
                r = KErrUsbInterfaceNotReady;
            }
        break;

    case RDevUsbcClient::EControlClearHaltEndpoint:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlClearHaltEndpoint"));
        if (iValidInterface && ValidEndpoint((TInt) a1))
            {
            r = iController->ClearHaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber());
            }
        else
            {
            if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured)
                r = KErrUsbDeviceNotConfigured;
            else
                r = KErrUsbInterfaceNotReady;
            }
        break;

    case RDevUsbcClient::EControlDumpRegisters:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlDumpRegisters"));
        iController->DumpRegisters();
        break;

    case RDevUsbcClient::EControlReleaseDeviceControl:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseDeviceControl"));
        iController->ReleaseDeviceControl(this);
        iOwnsDeviceControl = EFalse;
        break;

    case RDevUsbcClient::EControlEndpointZeroMaxPacketSizes:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroMaxPacketSizes"));
        r = iController->EndpointZeroMaxPacketSizes();
        break;

    case RDevUsbcClient::EControlSetEndpointZeroMaxPacketSize:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointZeroMaxPacketSize"));
        r = iController->SetEndpointZeroMaxPacketSize(reinterpret_cast<TInt>(a1));
        break;

    case RDevUsbcClient::EControlGetEndpointZeroMaxPacketSize:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointZeroMaxPacketSize"));
        r = iController->Ep0PacketSize();
        break;

    case RDevUsbcClient::EControlGetDeviceDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptor"));
        r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient);
        if (r != KErrNone)
            PanicClientThread(r);
        r = iController->GetDeviceDescriptor(iClient, *((TDes8*) a1));
        break;

    case RDevUsbcClient::EControlSetDeviceDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceDescriptor"));
        if (a1 != NULL)
            r = iController->SetDeviceDescriptor(iClient, *((TDes8*) a1));
        else
            r = KErrArgument;
        break;

    case RDevUsbcClient::EControlGetDeviceDescriptorSize:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptorSize"));
        if (a1 != NULL)
            r = iController->GetDeviceDescriptorSize(iClient, *((TDes8*) a1));
        else
            r = KErrArgument;
        break;

    case RDevUsbcClient::EControlGetConfigurationDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptor"));
        r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient);
        if (r != KErrNone)
            PanicClientThread(r);
        r = iController->GetConfigurationDescriptor(iClient, *((TDes8*) a1));
        break;

    case RDevUsbcClient::EControlGetConfigurationDescriptorSize:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptorSize"));
        if (a1 != NULL)
            {
            r = iController->GetConfigurationDescriptorSize(iClient, *((TDes8*) a1));
            }
        else
            r = KErrArgument;
        break;

    case RDevUsbcClient::EControlSetConfigurationDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationDescriptor"));
        r = iController->SetConfigurationDescriptor(iClient, *((TDes8*) a1));
        break;

    case RDevUsbcClient::EControlGetInterfaceDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptor"));
        r = iController->GetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2));
        break;

    case RDevUsbcClient::EControlGetInterfaceDescriptorSize:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptorSize"));
        r = iController->GetInterfaceDescriptorSize(iClient, this, (TInt) a1, *(TDes8*) a2);
        break;

    case RDevUsbcClient::EControlSetInterfaceDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterfaceDescriptor"));
        r = iController->SetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2));
        break;

    case RDevUsbcClient::EControlGetEndpointDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptor"));
        r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
        if (r != KErrNone)
            PanicClientThread(r);
        ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
        r = iController->GetEndpointDescriptor(iClient, this, epInfo.iSetting,
                                               ep, *(TDes8*) epInfo.iArg);
        break;

    case RDevUsbcClient::EControlGetEndpointDescriptorSize:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptorSize"));
        r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
        if (r != KErrNone)
            PanicClientThread(r);
        ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
        r = iController->GetEndpointDescriptorSize(iClient, this, epInfo.iSetting,
                                                   ep, *(TDes8*) epInfo.iArg);
        break;

    case RDevUsbcClient::EControlSetEndpointDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointDescriptor"));
        r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
        if (r != KErrNone)
            PanicClientThread(r);
        ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
        r = iController->SetEndpointDescriptor(iClient, this, epInfo.iSetting,
                                               ep, *(TDes8*)epInfo.iArg);
        break;

    case RDevUsbcClient::EControlGetDeviceQualifierDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceQualifierDescriptor"));
        r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient);
        if (r != KErrNone)
            PanicClientThread(r);
        r = iController->GetDeviceQualifierDescriptor(iClient, *((TDes8*) a1));
        break;

    case RDevUsbcClient::EControlSetDeviceQualifierDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceQualifierDescriptor"));
        if (a1 != NULL)
            r = iController->SetDeviceQualifierDescriptor(iClient, *((TDes8*) a1));
        else
            r = KErrArgument;
        break;

    case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtherSpeedConfigurationDescriptor"));
        r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient);
        if (r != KErrNone)
            PanicClientThread(r);
        r = iController->GetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1));
        break;

    case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtherSpeedConfigurationDescriptor"));
        r = iController->SetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1));
        break;


    case RDevUsbcClient::EControlGetCSInterfaceDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptor"));
        r = iController->GetCSInterfaceDescriptorBlock(iClient, this, (TInt) a1, *((TDes8*) a2));
        break;

    case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptorSize"));
        r = iController->GetCSInterfaceDescriptorBlockSize(iClient, this, (TInt) a1, *(TDes8*) a2);
        break;

    case RDevUsbcClient::EControlGetCSEndpointDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptor"));
        r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
        if (r != KErrNone)
            PanicClientThread(r);
        ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
        r = iController->GetCSEndpointDescriptorBlock(iClient, this, epInfo.iSetting,
                                                      ep, *(TDes8*) epInfo.iArg);
        break;

    case RDevUsbcClient::EControlGetCSEndpointDescriptorSize:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptorSize"));
        r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo));
        if (r != KErrNone)
            PanicClientThread(r);
        ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint);
        r = iController->GetCSEndpointDescriptorBlockSize(iClient, this, epInfo.iSetting,
                                                          ep, *(TDes8*) epInfo.iArg);
        break;

    case RDevUsbcClient::EControlSignalRemoteWakeup:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSignalRemoteWakeup"));
        r = iController->SignalRemoteWakeup();
        break;

    case RDevUsbcClient::EControlDeviceDisconnectFromHost:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceDisconnectFromHost"));
        r = iController->UsbDisconnect();
        break;

    case RDevUsbcClient::EControlDeviceConnectToHost:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceConnectToHost"));
        r = iController->UsbConnect();
        break;

    case RDevUsbcClient::EControlDevicePowerUpUdc:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlDevicePowerUpUdc"));
        r = iController->PowerUpUdc();
        break;

    case RDevUsbcClient::EControlSetDeviceControl:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl"));
        r = iController->SetDeviceControl(this);
        if (r == KErrNone)
            {
            iOwnsDeviceControl = ETrue;
            if (iEndpoint[0] == NULL)
                {
                __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl 11"));
                r = SetupEp0();
                if (r != KErrNone)
                    {
                    __KTRACE_OPT(KPANIC, Kern::Printf("  Error: SetupEp0() failed"));
                    iController->ReleaseDeviceControl(this);
                    DestroyEp0();
                    iOwnsDeviceControl = EFalse;
                    }
                iEndpoint[0]->TryToStartRead(EFalse);
                }
            }
        else
            r = KErrInUse;
        break;

    case RDevUsbcClient::EControlCurrentlyUsingHighSpeed:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlCurrentlyUsingHighSpeed"));
        r = iController->CurrentlyUsingHighSpeed();
        break;

    case RDevUsbcClient::EControlSetInterface:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterface"));
        r = Kern::ThreadRawRead(iClient, a2, &ifcInfo, sizeof(ifcInfo));
        if (r != KErrNone)
            PanicClientThread(r);
        if (iValidInterface && (iDeviceState == UsbShai::EUsbPeripheralStateConfigured))
            {
            r = KErrGeneral;
            }
        else
            {
            bandwidthPriority = ifcInfo.iBandwidthPriority;
            if ((bandwidthPriority & 0xffffff00) ||
                ((bandwidthPriority & 0x0f) >= KUsbcDmaBufMaxPriorities) ||
                (((bandwidthPriority >> 4) & 0x0f) >= KUsbcDmaBufMaxPriorities))
                {
                r = KErrArgument;
                }
            else
                {
                r = SetInterface((TInt) a1, &ifcInfo);
                }
            }
            
        break;
		

    case RDevUsbcClient::EControlGetChargerDetectorCaps:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetChargerDetectorCaps"));
		iController->ChargerDetectorCaps(chargingPro);          		
        r = Kern::ThreadRawWrite(iClient, a1, &chargingPro, sizeof(chargingPro), iClient);
        if (r != KErrNone)
        	{
            PanicClientThread(r);
            }
        break;		

    case RDevUsbcClient::EControlReleaseInterface:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseInterface"));
        r = iController->ReleaseInterface(this, (TInt) a1);
        if (r == KErrNone)
            {
            DestroyInterface((TUint) a1);
            }
        else
            {
            __KTRACE_OPT(KPANIC, Kern::Printf("  Error in PIL: LDD interface won't be released."));
            }
        break;

    case RDevUsbcClient::EControlSetCSInterfaceDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSInterfaceDescriptor"));
        r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo));
        if (r != KErrNone)
            PanicClientThread(r);
        r = iController->SetCSInterfaceDescriptorBlock(iClient, this, desInfo.iSetting,
                                                       *reinterpret_cast<const TDes8*>(desInfo.iArg),
                                                       desInfo.iSize);
        break;

    case RDevUsbcClient::EControlSetCSEndpointDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSEndpointDescriptor"));
        r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo));
        if (r != KErrNone)
            PanicClientThread(r);
        ep = EpFromAlternateSetting(desInfo.iSetting, desInfo.iEndpoint);
        r = iController->SetCSEndpointDescriptorBlock(iClient, this, desInfo.iSetting, ep,
                                                      *reinterpret_cast<const TDes8*>(desInfo.iArg),
                                                      desInfo.iSize);
        break;

    case RDevUsbcClient::EControlGetStringDescriptorLangId:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptorLangId"));
        r = iController->GetStringDescriptorLangId(iClient, *((TDes8*) a1));
        break;

    case RDevUsbcClient::EControlSetStringDescriptorLangId:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptorLangId"));
        r = iController->SetStringDescriptorLangId(reinterpret_cast<TUint>(a1));
        break;

    case RDevUsbcClient::EControlGetManufacturerStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetManufacturerStringDescriptor"));
        r = iController->GetManufacturerStringDescriptor(iClient, *((TPtr8*) a1));
        break;

    case RDevUsbcClient::EControlSetManufacturerStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetManufacturerStringDescriptor"));
        r = iController->SetManufacturerStringDescriptor(iClient, *((TPtr8*) a1));
        break;

    case RDevUsbcClient::EControlRemoveManufacturerStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveManufacturerStringDescriptor"));
        r = iController->RemoveManufacturerStringDescriptor();
        break;

    case RDevUsbcClient::EControlGetProductStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetProductStringDescriptor"));
        r = iController->GetProductStringDescriptor(iClient, *((TPtr8*) a1));
        break;

    case RDevUsbcClient::EControlSetProductStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetProductStringDescriptor"));
        r = iController->SetProductStringDescriptor(iClient, *((TPtr8*) a1));
        break;

    case RDevUsbcClient::EControlRemoveProductStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveProductStringDescriptor"));
        r = iController->RemoveProductStringDescriptor();
        break;

    case RDevUsbcClient::EControlGetSerialNumberStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetSerialNumberStringDescriptor"));
        r = iController->GetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1));
        break;

    case RDevUsbcClient::EControlSetSerialNumberStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetSerialNumberStringDescriptor"));
        r = iController->SetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1));
        break;

    case RDevUsbcClient::EControlRemoveSerialNumberStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveSerialNumberStringDescriptor"));
        r = iController->RemoveSerialNumberStringDescriptor();
        break;

    case RDevUsbcClient::EControlGetConfigurationStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationStringDescriptor"));
        r = iController->GetConfigurationStringDescriptor(iClient, *((TPtr8*) a1));
        break;

    case RDevUsbcClient::EControlSetConfigurationStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationStringDescriptor"));
        r = iController->SetConfigurationStringDescriptor(iClient, *((TPtr8*) a1));
        break;

    case RDevUsbcClient::EControlRemoveConfigurationStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveConfigurationStringDescriptor"));
        r = iController->RemoveConfigurationStringDescriptor();
        break;

    case RDevUsbcClient::EControlGetStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptor"));
        r = iController->GetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2));
        break;

    case RDevUsbcClient::EControlSetStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptor"));
        r = iController->SetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2));
        break;

    case RDevUsbcClient::EControlRemoveStringDescriptor:
        __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveStringDescriptor"));
        r = iController->RemoveStringDescriptor((TUint8) (TInt) a1);
        break;

    case RDevUsbcClient::EControlQueryEndpointResourceUse:
        epRes = (TUsbcEndpointResource)((TInt) a2);
        if (!ValidEndpoint((TInt)a1))
            {
            r = KErrUsbEpNotInInterface;
            }
        else
            {
            r = iController->QueryEndpointResource(this, iEndpoint[(TInt)a1]->RealEpNumber(), epRes);
            }
        break;

    case RDevUsbcClient::EControlSetOtgDescriptor:
        {
        r = iController->SetOtgDescriptor(iClient, *((const TDesC8*)a1));
        }
        break;

    case RDevUsbcClient::EControlGetOtgDescriptor:
        {
        r = iController->GetOtgDescriptor(iClient, *((TDes8*)a1));
        }
        break;

    case RDevUsbcClient::EControlGetOtgFeatures:
        {
        r = iController->GetOtgFeatures(iClient, *((TDes8*)a1));
        }
        break;

    default:
        __KTRACE_OPT(KUSB, Kern::Printf("Function code not supported"));
        r = KErrNotSupported;
        }

    return r;
    }


TInt DLddUsbcChannel::SetInterface(TInt aInterfaceNumber, TUsbcIfcInfo* aInfoBuf)
    {
    TUsbcInterfaceInfoBuf ifc_info_buf;
    TUsbcInterfaceInfoBuf* const ifc_info_buf_ptr = aInfoBuf->iInterfaceData;
    const TInt srcLen = Kern::ThreadGetDesLength(iClient, ifc_info_buf_ptr);
    if (srcLen < ifc_info_buf.Length())
        {
        __KTRACE_OPT(KUSB, Kern::Printf("SetInterface can't copy"));
        PanicClientThread(EDesOverflow);
        }

    TInt r = Kern::ThreadDesRead(iClient, ifc_info_buf_ptr, ifc_info_buf, 0, KChunkShiftBy0);
    if (r != KErrNone)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Copy failed reason=%d", r));
        PanicClientThread(r);
        }

    TUsbcEndpointInfo* pEndpointData = ifc_info_buf().iEndpointData;

    // If an alternate interface is being asked for then do nothing,
    // just pass it down to the Controller.
    const TInt num_endpoints = ifc_info_buf().iTotalEndpointsUsed;
    __KTRACE_OPT(KUSB, Kern::Printf("SetInterface num_endpoints=%d", num_endpoints));

    // [The next 4 variables have to be initialized here because of the goto's that follow.]
    // Both IN and OUT buffers will be fully cached:
    const TUint32 cacheAttribs = EMapAttrSupRw | EMapAttrCachedMax;
    const TUint32 bandwidthPriority = aInfoBuf->iBandwidthPriority;

    // Supports ep0+5 endpoints
    TInt real_ep_numbers[6] = {-1, -1, -1, -1, -1, -1};

    // See if PIL will accept this interface
    __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Calling controller"));
    r = iController->SetInterface(this,
                                  iClient,
                                  aInterfaceNumber,
                                  ifc_info_buf().iClass,
                                  aInfoBuf->iString,
                                  ifc_info_buf().iTotalEndpointsUsed,
                                  ifc_info_buf().iEndpointData,
                                  &real_ep_numbers,
                                  ifc_info_buf().iFeatureWord);

    __KTRACE_OPT(KUSB, Kern::Printf("SetInterface controller returned %d", r));
    if (r != KErrNone)
        {
        __KTRACE_OPT(KPANIC, Kern::Printf("SetInterface failed reason=%d", r));
        return r;
        }

    // [The next variable has to be initialized here because of the goto's that follow.]
    TUsbcAlternateSettingList* alternateSettingListRec;

    // ep0
    if (iEndpoint[0] == NULL)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("SetInterface 11"));
        r = SetupEp0();
        if (r != KErrNone)
            {
            __KTRACE_OPT(KPANIC, Kern::Printf("  Error: SetupEp0() failed"));
            DestroyEp0();
            goto F1;
            }
        }

    alternateSettingListRec = new TUsbcAlternateSettingList;
    if (!alternateSettingListRec)
        {
        r = KErrNoMemory;
        goto F1;
        }

    __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::SetInterface num_endpoints=%d", num_endpoints));

    // other endpoints
    // calculate the total buffer size
    for (TInt i = 1; i <= num_endpoints; i++, pEndpointData++)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d", i));
        if (!ValidateEndpoint(pEndpointData))
            {
            r = KErrUsbBadEndpoint;
            goto F2;
            }

        TUsbcEndpoint* ep = new TUsbcEndpoint(this, iController, pEndpointData, i, bandwidthPriority);
        alternateSettingListRec->iEndpoint[i] = ep;
        if (!ep)
            {
            r = KErrNoMemory;
            goto F2;
            }
        if (ep->Construct() != KErrNone)
            {
            r = KErrNoMemory;
            goto F2;
            }

        __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d rec=0x%08x ep==0x%08x",
                                        i, alternateSettingListRec, ep));
        }

    // buf size of each endpoint
    TInt bufSizes[KMaxEndpointsPerClient + 1];
    TInt epNum[KMaxEndpointsPerClient + 1];

    // init
    for( TInt i=0;i<KMaxEndpointsPerClient+1;i++ )
        {
        bufSizes[i] = -1;
        epNum[i] = i;
        }

    // Record the actual buf size of each endpoint
    for( TInt i=1;i<=num_endpoints;i++ )
        {
        bufSizes[i] = alternateSettingListRec->iEndpoint[i]->BufferSize();
        }

    __KTRACE_OPT(KUSB, Kern::Printf("Sort the endpoints:"));

    // sort the endpoint number by the bufsize decreasely
    for( TInt i=1;i<num_endpoints;i++ )
        {
        TInt epMaxBuf = i;
        for(TInt k=i+1;k<=num_endpoints;k++ )
            {
            if( bufSizes[epMaxBuf]<bufSizes[k])
                {
                epMaxBuf = k;
                }
            }
        TInt temp = bufSizes[i];
        bufSizes[i] = bufSizes[epMaxBuf];
        bufSizes[epMaxBuf] = temp;

        temp = epNum[i];
        epNum[i] = epNum[epMaxBuf];
        epNum[epMaxBuf] = temp;

        alternateSettingListRec->iEpNumDeOrderedByBufSize[i] = epNum[i];

        __KTRACE_OPT(KUSB, Kern::Printf(" %d:%d", epNum[i], bufSizes[i]));
        }
    alternateSettingListRec->iEpNumDeOrderedByBufSize[num_endpoints] = epNum[num_endpoints];
    __KTRACE_OPT(KUSB, Kern::Printf(" %d:%d", epNum[num_endpoints], bufSizes[num_endpoints]));
    __KTRACE_OPT(KUSB, Kern::Printf("\n"));

    // chain in this alternate setting
    alternateSettingListRec->iNext = iAlternateSettingList;
    iAlternateSettingList = alternateSettingListRec;
    alternateSettingListRec->iSetting = aInterfaceNumber;
    alternateSettingListRec->iNumberOfEndpoints = num_endpoints;

    // Record the 'real' endpoint number used by the PDD in both the Ep and
    // the Req callback:
    for (TInt i = 1; i <= num_endpoints; i++)
        {
        alternateSettingListRec->iEndpoint[i]->SetRealEpNumber(real_ep_numbers[i]);
        }

    r = SetupInterfaceMemory(iHwChunks, cacheAttribs );
    if( r==KErrNone )
        {
        __KTRACE_OPT(KUSB, Kern::Printf("SetInterface ready to exit"));
    
        if (aInterfaceNumber == 0)
            {
            // make sure we're ready to go with the main interface
            iValidInterface = ETrue;
            __KTRACE_OPT(KUSB, Kern::Printf("SetInterface SelectAlternateSetting"));
            SelectAlternateSetting(0);
            }
        return KErrNone;
        }
    else
        {
        __KTRACE_OPT(KUSB, Kern::Printf("Destroying all interfaces"));
        DestroyAllInterfaces();
        DestroyEp0();
        return r;
        }

 F2:
    delete alternateSettingListRec;
    //Fall through
 
 F1:
#if _DEBUG
    TInt r1 = iController->ReleaseInterface(this, aInterfaceNumber);
    __KTRACE_OPT(KUSB, Kern::Printf("Release Interface controller returned %d", r1));
#else
    (void)    iController->ReleaseInterface(this, aInterfaceNumber);
#endif
    return r;
    }

// realloc the memory, and set the previous interfaces 
TInt DLddUsbcChannel::SetupInterfaceMemory(RArray<DPlatChunkHw*> &aHwChunks, 
        TUint32 aCacheAttribs )
    {
    TUsbcAlternateSettingList* asRec = iAlternateSettingList;

    // if buffers has been changed
    TBool chunkChanged = EFalse;
    TInt numOfEp = asRec->iNumberOfEndpoints;
 
    // 1, collect all bufs' sizes for the current interface
    //    to realloc all the chunks
    __KTRACE_OPT(KUSB, Kern::Printf("Collect all buffer sizes:"));
    RArray<TInt> bufSizes;
    for(TInt i=1;i<=numOfEp;i++)
        {
        TInt nextEp = asRec->iEpNumDeOrderedByBufSize[i];
        TInt epBufCount = asRec->iEndpoint[nextEp]->BufferNumber();
        __KTRACE_OPT(KUSB, Kern::Printf(" ep %d, buf count %d", nextEp, epBufCount ));
        for(TInt k=0;k<epBufCount;k++)
            {
            TInt epBufSize = asRec->iEndpoint[nextEp]->BufferSize();
            TInt r = bufSizes.Append(epBufSize);
            if(r!=KErrNone)
                {
                iController->DeRegisterClient(this);
                bufSizes.Close();
                return r;
                }
            __KTRACE_OPT(KUSB,Kern::Printf(" %d", epBufSize ));
            }
        __KTRACE_OPT(KUSB, Kern::Printf("\n"));

        }
   
    // 2, alloc the buffer decreasely, biggest-->smallest
    //   2.1 check the existing chunks
    TInt bufCount = bufSizes.Count();
    __KTRACE_OPT(KUSB, Kern::Printf(" ep buf number needed %d", bufCount ));
    __KTRACE_OPT(KUSB, Kern::Printf(" chunks available %d", aHwChunks.Count() ));

    TInt chunkInd = 0;
    while( (chunkInd<aHwChunks.Count())&& (chunkInd<bufCount))
        {
        TUint8* oldAddr = NULL;
        oldAddr = reinterpret_cast<TUint8*>(aHwChunks[chunkInd]->LinearAddress());

        DPlatChunkHw* chunk = ReAllocate(bufSizes[chunkInd], aHwChunks[chunkInd], aCacheAttribs);
        if (chunk == NULL)
            {
            __KTRACE_OPT(KUSB, Kern::Printf("Failed to alloc chunks size %d!", bufSizes[chunkInd]));
            // lost all interfaces:
            // Tell Controller to release Interface and h/w resources associated with this
            iController->DeRegisterClient(this);
            bufSizes.Close();
            return KErrNoMemory;
            }
        else
            {
            // Parcel out the memory between endpoints
            TUint8* newAddr = reinterpret_cast<TUint8*>(chunk->LinearAddress());
            __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory alloc new chunk=0x%x, size=%d", newAddr,bufSizes[chunkInd]));
            // The check is important to avoid chunkChanged to be corrupted.
            // This code change is to fix the problem that one chunk is used by multiple interfaces.
            if(!chunkChanged)
                {
                chunkChanged = (newAddr != oldAddr);
                }            
            aHwChunks[chunkInd] = chunk;
            }
        chunkInd++;
        }
    
    //   2.2 in case available chunks are not enough
    while( chunkInd<bufCount)
        {
        DPlatChunkHw* chunk = NULL;
        chunk = Allocate( bufSizes[chunkInd], aCacheAttribs);
        if (chunk == NULL)
            {
            __KTRACE_OPT(KUSB, Kern::Printf("Failed to alloc chunk, size %d!", bufSizes[chunkInd]));
            // lost all interfaces:
            // Tell Controller to release Interface and h/w resources associated with this
            iController->DeRegisterClient(this);
            bufSizes.Close();
            return KErrNoMemory;
            }
        else
            {
            // Parcel out the memory between endpoints
            __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory alloc new chunk=0x%x, size=%d",
                                    reinterpret_cast<TUint8*>(chunk->LinearAddress()), bufSizes[chunkInd]));
            TInt r = aHwChunks.Append(chunk);
            if(r!=KErrNone)
                {
                ClosePhysicalChunk(chunk);
                iController->DeRegisterClient(this);
                bufSizes.Close();
                return r;
                }
            }
        chunkInd++;
        }

    // 3, Set the the bufs of the interfaces
    
    ReSetInterfaceMemory(asRec, aHwChunks);

    if(chunkChanged)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory readdressing."));
        asRec = asRec->iNext;
        while (asRec)
            {
            // Interfaces are not concurrent so they can all start at the same logical address
            __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory readdressing setting=%d", asRec->iSetting));
            ReSetInterfaceMemory(asRec, aHwChunks);
            asRec = asRec->iNext;
            }
        }
    return KErrNone;
    }

TInt DLddUsbcChannel::SetupEp0()
    {
    __KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 entry %x", this));
    TInt ep0Size = iController->Ep0PacketSize();
    TUsbcEndpointInfo ep0Info = TUsbcEndpointInfo(UsbShai::KUsbEpTypeControl, UsbShai::KUsbEpDirBidirect, ep0Size);
    TUsbcEndpoint* ep0 = new TUsbcEndpoint(this, iController, &ep0Info, 0, 0);
    if (ep0 == NULL)
        {
        return KErrNoMemory;
        }
    // In case we have to return early:
    iEndpoint[0] = ep0;
    TInt r = ep0->Construct();
    if (r != KErrNone)
        {
        return KErrNoMemory;
        }

    TInt bufferNum = ep0->BufferNumber();
    TInt bufferSize = ep0->BufferSize();
    TUint32 cacheAttribs = EMapAttrSupRw | EMapAttrCachedMax;

    for(TInt i=0;i<bufferNum;i++)
        {
        DPlatChunkHw* chunk = Allocate(bufferSize, cacheAttribs );
        if(chunk==NULL)
            {
            return KErrNoMemory;
            }
        TInt r = iHwChunksEp0.Append(chunk);
        if(r!=KErrNone)
            {
            ClosePhysicalChunk(chunk);
            return r;
            }
        TUint8 * buf;
        buf = (TUint8*) chunk->LinearAddress();
        ep0->SetBufferAddr( i, buf);
        __KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 60 buffer number %d", i));
        __KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 60 buffer size %d", bufferSize));
        }

    ep0->SetRealEpNumber(0);
    return KErrNone;
    }

// Set buffer address of the interface
// Precondition: Enough chunks available.
void DLddUsbcChannel::ReSetInterfaceMemory(TUsbcAlternateSettingList* aAlternateSettingListRec,
        RArray<DPlatChunkHw*> &aHwChunks)
    {
    TUsbcAlternateSettingList* asRec = aAlternateSettingListRec;

    // set all the interfaces
    TInt chunkInd = 0;
    TInt numOfEp = asRec->iNumberOfEndpoints;

    for (TInt i = 1; i <= numOfEp; i++)
        {
        TInt nextEp = asRec->iEpNumDeOrderedByBufSize[i];
        TInt epBufCount = asRec->iEndpoint[nextEp]->BufferNumber();
        for(TInt k=0;k<epBufCount;k++)
            {
            TUsbcEndpoint* ep = asRec->iEndpoint[nextEp];
            if (ep != NULL )
                {
                TUint8* pBuf = NULL;
                pBuf = reinterpret_cast<TUint8*>(aHwChunks[chunkInd]->LinearAddress());
                ep->SetBufferAddr( k, pBuf);
                __KTRACE_OPT(KUSB, Kern::Printf("  ep %d, buf %d, addr 0x%x", nextEp, k, pBuf ));
                chunkInd++;
                __ASSERT_DEBUG(chunkInd<=aHwChunks.Count(),
                               Kern::Printf("  Error: available chunks %d, run out at epInd%d, bufInd%d",
                                       aHwChunks.Count(), i, k));
                __ASSERT_DEBUG(chunkInd<=aHwChunks.Count(),
                                   Kern::Fault("usbc.ldd", __LINE__));
                }
            }
        }

    }

void DLddUsbcChannel::DestroyAllInterfaces()
    {
    // Removes all interfaces
    TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
    while (alternateSettingListRec)
        {
        iController->ReleaseInterface(this, alternateSettingListRec->iSetting);
        TUsbcAlternateSettingList* alternateSettingListRecNext = alternateSettingListRec->iNext;
        delete alternateSettingListRec;
        alternateSettingListRec = alternateSettingListRecNext;
        }
    iNumberOfEndpoints = 0;
    iAlternateSettingList = NULL;

    for(TInt i=0;i<iHwChunks.Count();i++)
        {
        ClosePhysicalChunk( iHwChunks[i]);
        }
    iHwChunks.Close();

    iValidInterface = EFalse;
    }


void DLddUsbcChannel::DestroyInterface(TUint aInterfaceNumber)
    {
    if (iAlternateSetting == aInterfaceNumber)
        {
        ResetInterface(KErrUsbInterfaceNotReady);
        iValidInterface = EFalse;
        iNumberOfEndpoints = 0;
        for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
            {
            iEndpoint[i] = NULL;
            }
        }
    TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
    TUsbcAlternateSettingList* alternateSettingListRecOld = NULL;
    while (alternateSettingListRec)
        {
        TUsbcAlternateSettingList* alternateSettingListRecNext = alternateSettingListRec->iNext;
        if (alternateSettingListRec->iSetting == aInterfaceNumber)
            {
            // This record is to be deleted
            if (alternateSettingListRecOld == NULL)
                {
                // The record to be deleted is at the list head
                iAlternateSettingList = alternateSettingListRecNext;
                }
            else
                {
                // The record to be deleted is NOT at the list head
                alternateSettingListRecOld->iNext = alternateSettingListRecNext;
                }
            delete alternateSettingListRec;
            break;
            }
        alternateSettingListRecOld = alternateSettingListRec;
        alternateSettingListRec = alternateSettingListRecNext;
        }

    if (iAlternateSettingList == NULL)
        {
        // if no interfaces left destroy non-ep0 buffering
        for(TInt i=0;i<iHwChunks.Count();i++)
            {
            ClosePhysicalChunk( iHwChunks[i]);
            }
        iHwChunks.Close();
        }
    }


void DLddUsbcChannel::DestroyEp0()
    {
    delete iEndpoint[0];
    iEndpoint[0] = NULL;
    for(TInt i=0;i<iHwChunksEp0.Count();i++)
        {
        ClosePhysicalChunk( iHwChunksEp0[i] );
        }
    iHwChunksEp0.Close();
    }


void DLddUsbcChannel::EndpointStatusChangeCallback(TAny* aDLddUsbcChannel)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback"));
    DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel;
    if (dUsbc->iChannelClosing)
        return;
    TUint endpointState = dUsbc->iEndpointStatusCallbackInfo.State();
    const TInt reqNo = (TInt) RDevUsbcClient::ERequestEndpointStatusNotify;
    if (dUsbc->iRequestStatus[reqNo])
        {
        __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback Notify status"));
        DThread* client = dUsbc->iClient;
        
        dUsbc->iEndpointStatusChangeReq->Data() = endpointState;
        dUsbc->iRequestStatus[reqNo] = NULL;
        Kern::QueueRequestComplete(client,dUsbc->iEndpointStatusChangeReq,KErrNone);
        dUsbc->iEndpointStatusChangePtr = NULL;
        }
    }


void DLddUsbcChannel::StatusChangeCallback(TAny* aDLddUsbcChannel)
    {
    DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel;
    if (dUsbc->iChannelClosing)
        return;

    TUsbcDeviceState deviceState;
    TInt i;
     for (i = 0;
          (i < KUsbcDeviceStateRequests) && ((deviceState = dUsbc->iStatusCallbackInfo.State(i)) != UsbShai::EUsbPeripheralNoState);
          ++i)
        {
         __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallBack status=%d", deviceState));
        if (deviceState & KUsbAlternateSetting)
            {
            dUsbc->ProcessAlternateSetting(deviceState);
            }
        else
            {
            dUsbc->ProcessDeviceState(deviceState);
            }
        // Only queue if userside is interested
        if (dUsbc->iDeviceStatusNeeded)
            {
            dUsbc->iStatusFifo->AddStatusToQueue(deviceState);
            const TInt reqNo = (TInt) RDevUsbcClient::ERequestAlternateDeviceStatusNotify;
            if (dUsbc->AlternateDeviceStateTestComplete())
                {
                    dUsbc->iRequestStatus[reqNo]=NULL;
                    Kern::QueueRequestComplete(dUsbc->iClient,dUsbc->iStatusChangeReq,KErrNone);
                }
            }
        }
     // We don't want to be interrupted in the middle of this:
    const TInt irqs = NKern::DisableInterrupts(2);
     dUsbc->iStatusCallbackInfo.ResetState();
    NKern::RestoreInterrupts(irqs);
    }


void DLddUsbcChannel::OtgFeatureChangeCallback(TAny* aDLddUsbcChannel)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback"));
    DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel;
    if (dUsbc->iChannelClosing)
        return;

    TUint8 features;
    // No return value check. Assume OTG always supported here
    dUsbc->iController->GetCurrentOtgFeatures(features);

    const TInt reqNo = (TInt) RDevUsbcClient::ERequestOtgFeaturesNotify;
    if (dUsbc->iRequestStatus[reqNo])
        {
        __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback Notify status"));
        dUsbc->iOtgFeatureChangeReq->Data()=features;
        dUsbc->iRequestStatus[reqNo] = NULL;
        Kern::QueueRequestComplete(dUsbc->iClient,dUsbc->iOtgFeatureChangeReq,KErrNone);
        dUsbc->iOtgFeatureChangePtr = NULL;
        }
    }

void DLddUsbcChannel::ChargerTypeChangeCallback(TAny* aDLddUsbcChannel)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("ChargerTypeChangeCallback"));
    DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel;
    if (dUsbc->iChannelClosing)
        return;   
    const TInt reqNo = (TInt) RDevUsbcClient::ERequestChargingPortTypeNotify;
    if (dUsbc->iRequestStatus[reqNo])
        {
        __KTRACE_OPT(KUSB, Kern::Printf("ChargerTypeChangeCallback Notify status"));        
        Kern::Printf("ChargerTypeChangeCallback Notify status");        
        TUint chargerType;
        chargerType = dUsbc->iChargerTypeCallbackInfo.ChargerType();
        dUsbc->iChargerTypeChangeReq->Data()=chargerType;
        dUsbc->iRequestStatus[reqNo] = NULL;
        Kern::QueueRequestComplete(dUsbc->iClient,dUsbc->iChargerTypeChangeReq,KErrNone);
        dUsbc->iChargerTypeChangePtr = NULL;
        dUsbc->iChargerTypeCallbackInfo.SetPendingNotify(EFalse);
        }    
    else
        {
        Kern::Printf("ChargerTypeChangeCallback Set pending notify");
        __KTRACE_OPT(KUSB, Kern::Printf("ChargerTypeChangeCallback Set pending notify"));
        dUsbc->iChargerTypeCallbackInfo.SetPendingNotify(ETrue);
        }
    }

TInt DLddUsbcChannel::SelectAlternateSetting(TUint aAlternateSetting)
    {
    TInt r = KErrGeneral;                                    // error code doesn't go userside
    TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
    while (alternateSettingListRec)
        {
        if (alternateSettingListRec->iSetting == aAlternateSetting)
            {
            // found the correct interface, now latch in new endpoint set
            for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
                {
                iEndpoint[i] = NULL;
                }
            iNumberOfEndpoints = alternateSettingListRec->iNumberOfEndpoints;
            r = KErrNone;
            for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
                {
                iEndpoint[i] = alternateSettingListRec->iEndpoint[i];
                }
            // Only after correct alternate setting has been chosen.
            UpdateEndpointSizes();
            }
        alternateSettingListRec = alternateSettingListRec->iNext;
        }
    return r;
    }


TInt DLddUsbcChannel::EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint)
    {
    TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
    while (alternateSettingListRec)
        {
        if (alternateSettingListRec->iSetting == aAlternateSetting)
            {
            if ((aEndpoint <= alternateSettingListRec->iNumberOfEndpoints) &&
                (aEndpoint >= 0))
                {
                return alternateSettingListRec->iEndpoint[aEndpoint]->RealEpNumber();
                }
            else
                {
                __KTRACE_OPT(KPANIC, Kern::Printf("  Error: aEndpoint %d wrong for aAlternateSetting %d",
                                                  aEndpoint, aAlternateSetting));
                return -1;
                }
            }
        alternateSettingListRec = alternateSettingListRec->iNext;
        }
    __KTRACE_OPT(KPANIC, Kern::Printf("  Error: no aAlternateSetting %d found", aAlternateSetting));
    return -1;
    }


TInt DLddUsbcChannel::ProcessAlternateSetting(TUint aAlternateSetting)
    {
    ResetInterface(KErrUsbInterfaceChange);                    // kill any outstanding transfers
    __KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting 0x%08x", aAlternateSetting));
    TUint newSetting = aAlternateSetting&(~KUsbAlternateSetting);
    __KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting selecting alternate setting 0x%08x", newSetting));
    TInt r = SelectAlternateSetting(newSetting);
    if (r != KErrNone)
        return r;
    StartEpReads();
    iAlternateSetting = newSetting;
    return KErrNone;
    }


TInt DLddUsbcChannel::ProcessDeviceState(TUsbcDeviceState aDeviceState)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("ProcessDeviceState(%d -> %d)", iDeviceState, aDeviceState));
    if (iDeviceState == aDeviceState)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("  No state change => nothing to be done."));
        return KErrNone;
        }
    if (iDeviceState == UsbShai::EUsbPeripheralStateSuspended)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("  Coming out of Suspend: old state = %d", iOldDeviceState));
        iDeviceState = iOldDeviceState;
        if (iDeviceState == aDeviceState)
            {
            __KTRACE_OPT(KUSB, Kern::Printf("  New state same as before Suspend => nothing to be done."));
            return KErrNone;
            }
        }
    TBool renumerateState = (aDeviceState == UsbShai::EUsbPeripheralStateConfigured);
    TBool deconfigured = EFalse;
    TInt cancellationCode = KErrNone;
    if (aDeviceState == UsbShai::EUsbPeripheralStateSuspended)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("  Suspending..."));
        iOldDeviceState = iDeviceState;
        // Put PSL into low power mode here
        }
    else
        {
        deconfigured = (iDeviceState == UsbShai::EUsbPeripheralStateConfigured &&
                        aDeviceState != UsbShai::EUsbPeripheralStateConfigured);
        if (iDeviceState == UsbShai::EUsbPeripheralStateConfigured)
            {
            if (aDeviceState == UsbShai::EUsbPeripheralStateUndefined)
                cancellationCode = KErrUsbCableDetached;
            else if (aDeviceState == UsbShai::EUsbPeripheralStateAddress)
                cancellationCode = KErrUsbDeviceNotConfigured;
            else if (aDeviceState == UsbShai::EUsbPeripheralStateDefault)
                cancellationCode = KErrUsbDeviceBusReset;
            else
                cancellationCode = KErrUsbDeviceNotConfigured;
            }
        }
    __KTRACE_OPT(KUSB, Kern::Printf("  %d --> %d", iDeviceState, aDeviceState));
    iDeviceState = aDeviceState;
    if (iValidInterface || iOwnsDeviceControl)
        {
        // This LDD may not own an interface. It could be some manager reenumerating
        // after its subordinate LDDs have setup their interfaces.
        if (deconfigured)
            {
            DeConfigure(cancellationCode);
            }
        else if (renumerateState)
            {
            // Update size of Ep0.
            iEndpoint[0]->SetMaxPacketSize(iController->Ep0PacketSize());
            // First cancel transfers on all endpoints
            ResetInterface(KErrUsbInterfaceChange);
            // Select main interface & latch in new endpoint set
            SelectAlternateSetting(0);
            // Here we go
            StartEpReads();
            }
        }

    const TInt reqNo = (TInt) RDevUsbcClient::ERequestReEnumerate;
    if (renumerateState && iRequestStatus[reqNo])
        {
        // This lot must be done if we are reenumerated
        CompleteBufferRequest(iClient, reqNo, KErrNone);
        }

    return KErrNone;
    }


void DLddUsbcChannel::UpdateEndpointSizes()
    {
    // The regular ones.
    TInt i = 0;
    while ((++i <= KMaxEndpointsPerClient) && iEndpoint[i])
        {
        const TInt size = iController->EndpointPacketSize(this, iEndpoint[i]->RealEpNumber());
        if (size < 0)
            {
            __KTRACE_OPT(KPANIC, Kern::Printf("  Error: Packet size < 0 for ep %d", i));
            continue;
            }
        iEndpoint[i]->SetMaxPacketSize(size);
        }
    __ASSERT_DEBUG(i == iNumberOfEndpoints + 1,
                   Kern::Printf("  Error: iNumberOfEndpoints wrong (%d)", iNumberOfEndpoints));
    }


DPlatChunkHw* DLddUsbcChannel::ReAllocate(TInt aBuffersize, DPlatChunkHw* aHwChunk, TUint32 aCacheAttribs)
    {
    DPlatChunkHw* chunk = aHwChunk;
    if ((!chunk) || (chunk->iSize < aBuffersize))
        {
        if (chunk)
            {
            ClosePhysicalChunk(chunk);
            }
        __KTRACE_OPT(KUSB, Kern::Printf("ReAllocate need to get new chunk"));
        chunk = Allocate(aBuffersize, aCacheAttribs);
        }
    return chunk;
    }


DPlatChunkHw* DLddUsbcChannel::Allocate(TInt aBuffersize, TUint32 aCacheAttribs)
    {
    TUint32 physAddr = 0;
    TUint32 size = Kern::RoundToPageSize(aBuffersize);

    if (Epoc::AllocPhysicalRam(size, physAddr) != KErrNone)
        return NULL;

    DPlatChunkHw* HwChunk;
    if (DPlatChunkHw::New(HwChunk, physAddr, aBuffersize, aCacheAttribs) != KErrNone)
        {
        Epoc::FreePhysicalRam(physAddr, size);
        return NULL;
        }

    return HwChunk;
    }


TInt DLddUsbcChannel::DoRxComplete(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint, TBool aReEntrant)
    {
    TBool completeNow;
    TInt err = aTUsbcEndpoint->CopyToClient(iClient, completeNow,iClientAsynchNotify[aEndpoint]->iClientBuffer);
    if (completeNow)
        {
        aTUsbcEndpoint->SetClientReadPending(EFalse);
        CompleteBufferRequest(iClient, aEndpoint, err);
        }
    aTUsbcEndpoint->TryToStartRead(aReEntrant);
    return err;
    }


void DLddUsbcChannel::DoRxCompleteNow(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint)
    {
    aTUsbcEndpoint->SetClientReadPending(EFalse);
    CompleteBufferRequest(iClient, aEndpoint, KErrCancel);
    }


void DLddUsbcChannel::DoTxComplete(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint, TInt aError)
    {
    aTUsbcEndpoint->SetClientWritePending(EFalse);
    CompleteBufferRequest(iClient, aEndpoint, aError);
    }


TBool DLddUsbcChannel::AlternateDeviceStateTestComplete()
    {
    TBool completeNow = EFalse;
    const TInt reqNo = (TInt) RDevUsbcClient::ERequestAlternateDeviceStatusNotify;
    if (iRequestStatus[reqNo])
        {
        // User req is outstanding
        TUint32 deviceState;
        if (iStatusFifo->GetDeviceQueuedStatus(deviceState) == KErrNone)
            {
            // Device state waiting to be sent userside
            completeNow = ETrue;
            __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallback Notify status"));
            iStatusChangeReq->Data()=deviceState;
            iStatusChangePtr = NULL;
            }
        }
    return completeNow;
    }


void DLddUsbcChannel::EmergencyCompleteDfc(TAny* aDLddUsbcChannel)
    {
    ((DLddUsbcChannel*) aDLddUsbcChannel)->DoEmergencyComplete();
    }


void DLddUsbcChannel::DeConfigure(TInt aErrorCode)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::DeConfigure()"));
    // Called after deconfiguration. Cancels transfers on all endpoints.
    ResetInterface(aErrorCode);
    // Cancel the endpoint status notify request if it is outstanding.
    const TInt KEpNotReq = RDevUsbcClient::ERequestEndpointStatusNotify;
    if (iRequestStatus[KEpNotReq])
        {
        CancelNotifyEndpointStatus();
        iRequestStatus[KEpNotReq]=NULL;
        Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,aErrorCode);
        }
    // We have to reset the alternate setting number when the config goes away.
     SelectAlternateSetting(0);
    iAlternateSetting = 0;
    }


void DLddUsbcChannel::StartEpReads()
    {
    // Queued after enumeration. Starts reads on all endpoints.
    // The endpoint itself decides if it can do a read
    TInt i;
    for (i = 0; i <= iNumberOfEndpoints; i++)
        {
        // The endpoint itself will decide if it can read
        iEndpoint[i]->TryToStartRead(EFalse);
        }
    }


void DLddUsbcChannel::ResetInterface(TInt aErrorCode)
    {
    // Called after change in alternate setting.  Cancels transfers on all endpoints
    if (iValidInterface || iOwnsDeviceControl)
        {
        // Reset each endpoint except ep0
        for (TInt i = 1; i <= iNumberOfEndpoints; i++)
            {
            __KTRACE_OPT(KUSB, Kern::Printf("Cancelling transfer ep=%d", i));
            iEndpoint[i]->CancelTransfer(iClient,iClientAsynchNotify[i]->iClientBuffer);            // Copies data userside
            iEndpoint[i]->AbortTransfer();                    // kills any ldd->pil outstanding transfers
            iEndpoint[i]->iDmaBuffers->Flush();
            if (iRequestStatus[i] != NULL)
                CompleteBufferRequest(iClient, i, aErrorCode);
            iEndpoint[i]->SetClientWritePending(EFalse);
            iEndpoint[i]->SetClientReadPending(EFalse);
            }
        }
    }


void DLddUsbcChannel::AbortInterface()
    {
    // Called after when channel is closing
    if (iValidInterface || iOwnsDeviceControl)
        {
        for (TInt i = 0; i <= iNumberOfEndpoints; i++)
            {
            if (iEndpoint[i])
                {
                // kills any LDD->PDD outstanding transfers
                iEndpoint[i]->AbortTransfer();
                }
            }
        }
    }


void DLddUsbcChannel::ClosePhysicalChunk(DPlatChunkHw*& aHwChunk)
    {
    if (aHwChunk)
        {
         const TPhysAddr addr = aHwChunk->PhysicalAddress();
         const TInt size = aHwChunk->iSize;
        aHwChunk->Close(NULL);
         Epoc::FreePhysicalRam(addr, size);
        }
    aHwChunk = NULL;
    }


TInt DLddUsbcChannel::DoEmergencyComplete()
    {
    __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::DoEmergencyComplete"));
    // cancel any pending DFCs
    // complete all client requests
    for (TInt i = 0; i < KUsbcMaxRequests; i++)
        {
        if (iRequestStatus[i])
            {
            __KTRACE_OPT(KUSB, Kern::Printf("Complete request 0x%x", iRequestStatus[i]));

            if (i == RDevUsbcClient::ERequestAlternateDeviceStatusNotify)
                {

                iDeviceStatusNeeded = EFalse;
                iStatusFifo->FlushQueue();

                if (iStatusChangePtr)
                    {
                    iStatusChangeReq->Data() = iController->GetDeviceStatus();
                    iStatusChangePtr = NULL;

                    if (iStatusChangeReq->IsReady())
                        {
                        iRequestStatus[i] = NULL;
                        Kern::QueueRequestComplete(iClient, iStatusChangeReq,
                                KErrDisconnected);
                        }
                    }

                }
            else if (i == RDevUsbcClient::ERequestEndpointStatusNotify)
                {
                    
                   if (iEndpointStatusChangePtr)
                    {
                    TUint epBitmap = 0;
                    for (TInt i = 0; i <= iNumberOfEndpoints; i++)
                        {
                        TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber());
                        TUint b;
                        (v == EEndpointStateStalled) ? b = 1 : b = 0;
                        epBitmap |= b << i;
                        }    

                    iEndpointStatusChangeReq->Data() = epBitmap;
                    iEndpointStatusChangePtr = NULL;
                    }

                if (iEndpointStatusChangeReq->IsReady())
                    {
                    iRequestStatus[i] = NULL;
                    Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,KErrDisconnected);
                    }

                }
            else if (i == RDevUsbcClient::ERequestOtgFeaturesNotify)
                {
                    
                if (iOtgFeatureChangePtr)
                    {
                    TUint8 features;
                    iController->GetCurrentOtgFeatures(features);
                    iOtgFeatureChangeReq->Data()=features;
                    iOtgFeatureChangePtr = NULL;
                    }
                    
                if (iOtgFeatureChangeReq->IsReady())
                    {
                    iRequestStatus[i] = NULL;
                    Kern::QueueRequestComplete(iClient, iOtgFeatureChangeReq,
                            KErrDisconnected);
                    }

                }
	        else if (i == RDevUsbcClient::ERequestChargingPortTypeNotify)
	                {
	                    
	                if (iChargerTypeChangePtr)
	                    {
				        TUint chargerType;
				        chargerType = iChargerTypeCallbackInfo.ChargerType();
				        iChargerTypeChangeReq->Data()=chargerType;
						iChargerTypeChangePtr = NULL;
	                    }
	                    
	                if (iChargerTypeChangeReq->IsReady())
	                    {
	                    iRequestStatus[i] = NULL;
	                    Kern::QueueRequestComplete(iClient, iChargerTypeChangeReq,
	                            KErrDisconnected);
	                    }

	                }			
            else
                {
                CompleteBufferRequest(iClient, i, KErrDisconnected);
                }

            }
        }

    iStatusCallbackInfo.Cancel();
    iEndpointStatusCallbackInfo.Cancel();
    iOtgFeatureCallbackInfo.Cancel();
    iChargerTypeCallbackInfo.Cancel();
	return KErrNone;
	}


void DLddUsbcChannel::PanicClientThread(TInt aReason)
    {
    Kern::ThreadKill(iClient, EExitPanic, aReason, KUsbLDDKillCat);
    }


// ===============Endpoint====================

// Constructor
TUsbcEndpoint::TUsbcEndpoint(DLddUsbcChannel* aLDD, DUsbClientController* aController,
                             const TUsbcEndpointInfo* aEndpointInfo, TInt aEndpointNum,
                             TInt aBandwidthPriority)
    : iController(aController),
      iEndpointInfo(aEndpointInfo->iType, aEndpointInfo->iDir, aEndpointInfo->iSize),
      iClientReadPending(EFalse),
      iClientWritePending(EFalse),
      iEndpointNumber(aEndpointNum),
      iRealEpNumber(-1),
      iLdd(aLDD),
      iError(KErrNone),
      iRequestCallbackInfo(NULL),
      iBytesTransferred(0),
      iBandwidthPriority(aBandwidthPriority)
    {
     ResetTransferInfo();
    __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::TUsbcEndpoint 2"));
    }


TInt TUsbcEndpoint::Construct()
    {
    iDmaBuffers = new TDmaBuf(&iEndpointInfo, iBandwidthPriority);
    if (iDmaBuffers == NULL)
        {
        return KErrNoMemory;
        }
    const TInt r = iDmaBuffers->Construct(&iEndpointInfo);
    if (r != KErrNone)
        {
        return r;
        }
    iRequestCallbackInfo = new TUsbcRequestCallback(iLdd,
                                                    iEndpointNumber,
                                                    TUsbcEndpoint::RequestCallback,
                                                    this,
                                                    iLdd->iDfcQ,
                                                    KUsbRequestCallbackPriority);
    if (iRequestCallbackInfo == NULL)
        {
        return KErrNoMemory;
        }
    return KErrNone;
    }


TUsbcEndpoint::~TUsbcEndpoint()
    {
    __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::~TUsbcEndpoint(%d)", iEndpointNumber));
    AbortTransfer();
    delete iRequestCallbackInfo;
    delete iDmaBuffers;
    }


void TUsbcEndpoint::RequestCallback(TAny* aTUsbcEndpoint)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::RequestCallback"));
    ((TUsbcEndpoint*) aTUsbcEndpoint)->EndpointComplete();
    }


void TUsbcEndpoint::SetMaxPacketSize(TInt aSize)
    {
    iEndpointInfo.iSize = aSize;
    iDmaBuffers->SetMaxPacketSize(aSize);
    }


TInt TUsbcEndpoint::EndpointComplete()
    {
    __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete ep=%d %d",
                                    iEndpointNumber, iRequestCallbackInfo->iEndpointNum));

    if (iLdd->ChannelClosing())
        {
        __KTRACE_OPT(KUSB, Kern::Printf("We're going home -> completions no longer accepted"));
        return KErrNone;
        }

    UsbShai::TTransferDirection transferDir = iRequestCallbackInfo->iTransferDir;
    TInt error = iRequestCallbackInfo->iError;

    switch (transferDir)
        {

    case UsbShai::EControllerWrite:
        {
        __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete Write 2"));
        if (!iDmaBuffers->TxIsActive())
            {
            __KTRACE_OPT(KUSB, Kern::Printf("  TX completion but !iDmaBuffers->TxIsActive()"));
            break;
            }

        iDmaBuffers->TxSetInActive();
        TBool completeNow = EFalse;
        iBytesTransferred += iRequestCallbackInfo->iTxBytes;
        if (iClientWritePending)
            {
            //Complete Outstanding Write if necessary
            iError = error;
            if (iError != KErrNone)
                {
                completeNow = ETrue;
                if (iError == KErrPrematureEnd)                // Previous write could not be completed
                    iError = KErrNone;
                }
            else
                {
                if (iBytesTransferred == (TUint32) iTransferInfo.iTransferSize)
                    {
                    completeNow = ETrue;
                    }
                else
                    {
                    iError = ContinueWrite();
                    if (iError != KErrNone)
                        completeNow = ETrue;
                    }
                }
            if (completeNow)
                {
                TxComplete();
                ResetTransferInfo();
                if (iEndpointNumber == 0)
                    {
                    iDmaBuffers->Flush();
                    TryToStartRead(EFalse);
                    }
                }
            }
        break;
        }

    case UsbShai::EControllerRead:
        {
        // The first packet always contains the total #of bytes
        const TInt byteCount = iRequestCallbackInfo->iPacketSize[0];
        const TInt packetCount = iRequestCallbackInfo->iRxPackets;
        iDmaBuffers->ReadXferComplete(byteCount, packetCount, error);

        // We queue the dfc if we can complete the read, i.e. if we are reading a packet,
        // or if we have enough data to satisfy a read data request.
        if (iClientReadPending)
            {
            //Complete outstanding read
            __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete Read 3 (bytes "
                                            "available=%d)", iDmaBuffers->RxBytesAvailable()));
            TInt bytesReqd = iTransferInfo.iTransferSize - iBytesTransferred;
            TBool completeNow = EFalse;

            if (iTransferInfo.iTransferType == ETransferTypeReadPacket ||
                iTransferInfo.iTransferType == ETransferTypeReadOneOrMore)
                {
                // Always complete on a packet read
                completeNow = ETrue;
                }
            else if (iTransferInfo.iTransferType == ETransferTypeReadData)
                {
                // Complete only if enough data is present
                if (iDmaBuffers->RxBytesAvailable() >= bytesReqd)
                    completeNow = ETrue;
                }
            else if (iTransferInfo.iTransferType == ETransferTypeReadUntilShort)
                {
                // Complete if enough data is present or if a short packet has been delivered
                const TInt maxPacketSize = iEndpointInfo.iSize;
                const TInt lastPacketSize = iRequestCallbackInfo->iPacketSize[packetCount - 1];
                if (lastPacketSize < maxPacketSize)
                    completeNow = ETrue;
                else if (iDmaBuffers->RxBytesAvailable() >= bytesReqd)
                    completeNow = ETrue;
                else
                    {
                    const TUint type = iEndpointInfo.iType;
                    if ((type == UsbShai::KUsbEpTypeBulk) && (lastPacketSize & (maxPacketSize - 1)))
                        {
                        completeNow = ETrue;
                        }
                    else if ((type != UsbShai::KUsbEpTypeBulk) &&
                             (lastPacketSize > maxPacketSize) &&
                             (lastPacketSize % maxPacketSize))
                        {
                        completeNow = ETrue;
                        }
                    }
                }
            if (completeNow)
                {
                iError = error;
                RxComplete(EFalse);
                iClientReadPending = EFalse;
                }
            }
        iDmaBuffers->RxSetInActive();
        if (error != KErrNone)
            {
            return error;
            }
        if (TryToStartRead(EFalse) != KErrNone)
            {
//            if (iEndpointNumber != 0)
//                Kern::Printf("EndpointComplete couldn't start read on ep=%d", iEndpointNumber);
            }
        break;
        }

    default:
        // shouldn't get here
        break;
        }

    return KErrNone;
    }


void TUsbcEndpoint::TxComplete()
    {
    iLdd->DoTxComplete(this, iEndpointNumber, iError);
    }


TInt TUsbcEndpoint::RxComplete(TBool aReEntrant)
    {
    return iLdd->DoRxComplete(this, iEndpointNumber, aReEntrant);
    }


void TUsbcEndpoint::RxCompleteNow()
    {
    iLdd->DoRxCompleteNow(this, iEndpointNumber);
    }


TInt TUsbcEndpoint::CopyToClient(DThread* aClient, TClientBuffer *aTcb)
    {
    TBool completeNow;
    return CopyToClient(aClient, completeNow,aTcb);
    }


TInt TUsbcEndpoint::CopyToClient(DThread* aClient, TBool& aCompleteNow, TClientBuffer *aTcb)
    {
    TInt err;
    const TInt length = iTransferInfo.iTransferSize;
    const TBool KReadData = EFalse;
    const TBool KReadUntilShort = ETrue;

    __KTRACE_OPT(KUSB, Kern::Printf("CopyToClient: length = %d", length));

    if (iTransferInfo.iTransferType == ETransferTypeReadPacket)
        {
        err = iDmaBuffers->RxCopyPacketToClient(aClient, aTcb, length);
        aCompleteNow = ETrue;
        }
    else if (iTransferInfo.iTransferType == ETransferTypeReadOneOrMore)
        {
        err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred,
                                              KReadData, aCompleteNow);
        aCompleteNow = ETrue;
        }
    else if (iTransferInfo.iTransferType == ETransferTypeReadUntilShort)
        {
        err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred,
                                              KReadUntilShort, aCompleteNow);
        }
    else
        {
        err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred,
                                              KReadData, aCompleteNow);
        }

    if (aCompleteNow)
        {
        ResetTransferInfo();
        SetClientReadPending(EFalse);
        }

    return err;
    }


TInt TUsbcEndpoint::TryToStartRead(TBool aReEntrant)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead 1 ep=%d", iEndpointNumber));
    TInt r = KErrNone;
    if (iEndpointInfo.iDir != UsbShai::KUsbEpDirOut &&
        iEndpointInfo.iDir != UsbShai::KUsbEpDirBidirect)
        {
        // Verify ep direction
        __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead wrong direction ep=%d", iEndpointNumber));
        return KErrUsbEpBadDirection;
        }

    if (iEndpointNumber == 0)
        {
        // Can't issue an Ep0 read if reader or writer is active
        if (iDmaBuffers->TxIsActive())
            {
            __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead ep0 Tx already active FATAL"));
            return KErrUsbEpNotReady;
            }
        if (iDmaBuffers->RxIsActive())
            {
            __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead ep0 Rx already active non-FATAL"));
            }
        }

    if (!(iDmaBuffers->RxIsActive()))
        {
        TUint8* bufferAddr;
        TPhysAddr physAddr;
        TUsbcPacketArray* indexArray;
        TUsbcPacketArray* sizeArray;
        TInt length;
        r = iDmaBuffers->RxGetNextXfer(bufferAddr, indexArray, sizeArray, length, physAddr);
        if (r == KErrNone)
            {
            iDmaBuffers->RxSetActive();
            iRequestCallbackInfo->SetRxBufferInfo(bufferAddr, physAddr, indexArray, sizeArray, length);

            __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead 2 bufferAddr=0x%08x", bufferAddr));

            r = iController->SetupReadBuffer(*iRequestCallbackInfo);
            if (r != KErrNone)
                {
                iDmaBuffers->RxSetInActive();
                __KTRACE_OPT(KPANIC, Kern::Printf("  Error: TryToStartRead controller rejects read"));
                }
            }
        else
            {
            if (iClientReadPending)
                {
                // Deadlock, try to resolve it by draining buffer into descriptor
                if (!aReEntrant)
                    {
                    RxComplete(ETrue);
                    }
                else
                    {
                    // we are stuck, better complete userside otherwise the userside request will hang
                    RxCompleteNow();
                    }
                }
            }
        }
    return r;
    }


TInt TUsbcEndpoint::TryToStartWrite(TEndpointTransferInfo* pTfr)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("TryToStartWrite 1 ep=%d", iEndpointNumber));
    if (iEndpointInfo.iDir != UsbShai::KUsbEpDirIn &&
        iEndpointInfo.iDir != UsbShai::KUsbEpDirBidirect)
        {
        // Verify ep direction
        return KErrUsbEpBadDirection;
        }
    if (iEndpointNumber == 0)
        {
        // Can't issue an Ep0 write if unread data is available or writer is active
        if (iDmaBuffers->TxIsActive() || !iDmaBuffers->IsReaderEmpty())
            {
            return KErrUsbEpNotReady;
            }
        if (iDmaBuffers->RxIsActive())
            {
            // if a reader is active then cancel the read
            iDmaBuffers->RxSetInActive();
            iController->CancelReadBuffer(iLdd, iRealEpNumber);
            }
        }
    SetTransferInfo(pTfr);
    ContinueWrite();
    return KErrNone;
    }


TInt TUsbcEndpoint::ContinueWrite()
    {
    __KTRACE_OPT(KUSB, Kern::Printf("ContinueWrite 2"));
    TUint8* bufferAddr;
    TPhysAddr physAddr;
    TInt bufferLength;
    TInt r = iDmaBuffers->TxGetNextXfer(bufferAddr, bufferLength, physAddr);
    if (r != KErrNone)                                            // probably already active
        return r;
    __KTRACE_OPT(KUSB, Kern::Printf("ContinueWrite 3"));
    iDmaBuffers->TxSetActive();
    TBool zlpReqd = EFalse;
    TUint32 transferSize = iTransferInfo.iTransferSize;
    TInt length = Min(transferSize - iBytesTransferred, (TUint32) bufferLength);
    if (iBytesTransferred+length>=transferSize)
        {
        // only send a zlp if this is the last buffer of the transfer
        zlpReqd = iTransferInfo.iZlpReqd;
        }
    r = iDmaBuffers->TxStoreData(iLdd->Client(), iLdd->GetClientBuffer(iEndpointNumber), length, iBytesTransferred);
    if (r != KErrNone)
        return r;
    iDmaBuffers->TxSetActive();
    iRequestCallbackInfo->SetTxBufferInfo(bufferAddr, physAddr, length);
    iRequestCallbackInfo->iZlpReqd = zlpReqd;
#if 0
    for (TInt i = 0; i < iRequestCallbackInfo->iLength; i++)
        {
        __KTRACE_OPT(KUSB, Kern::Printf("Buffer[%d] = 0x%02x", i, iRequestCallbackInfo->iBufferStart[i]));
        }
#endif
    r = iController->SetupWriteBuffer(*iRequestCallbackInfo);
    return r;
    }


void TUsbcEndpoint::CancelTransfer(DThread* aThread, TClientBuffer *aTcb)
    {
    __KTRACE_OPT(KUSB, Kern::Printf("CancelTransfer"));
    if (iDmaBuffers != NULL)
        {
        if (iClientWritePending)
            {
            __KTRACE_OPT(KUSB, Kern::Printf("  (iClientWritePending)"));
            iClientWritePending = EFalse;
            iController->CancelWriteBuffer(iLdd, iRealEpNumber);
            iDmaBuffers->TxSetInActive();
            }
        if (iClientReadPending)
            {
            __KTRACE_OPT(KUSB, Kern::Printf("  (iClientReadPending)"));
            iClientReadPending = EFalse;
            CopyToClient(aThread,aTcb);
            }
        }
    }


void TUsbcEndpoint::AbortTransfer()
    {
    __KTRACE_OPT(KUSB, Kern::Printf("Abort Transfer"));
    if (iDmaBuffers != NULL)
        {
        if (iDmaBuffers->TxIsActive())
            {
            __KTRACE_OPT(KUSB, Kern::Printf("  (iClientWritePending)"));
            iController->CancelWriteBuffer(iLdd, iRealEpNumber);
            iDmaBuffers->TxSetInActive();
            }
        if (iDmaBuffers->RxIsActive())
            {
            __KTRACE_OPT(KUSB, Kern::Printf("  (iClientReadPending)"));
            iController->CancelReadBuffer(iLdd, iRealEpNumber);
            iDmaBuffers->RxSetInActive();
            }
        iRequestCallbackInfo->iDfc.Cancel();
        }
    }


TUsbcAlternateSettingList::TUsbcAlternateSettingList()
    : iNext(NULL),
      iNumberOfEndpoints(0),
      iSetting(0)
    {
    for (TInt i = 0; i <= KMaxEndpointsPerClient; i++)
        {
        iEpNumDeOrderedByBufSize[i] = -1;
        iEndpoint[i] = NULL;
        }
    }


TUsbcAlternateSettingList::~TUsbcAlternateSettingList()
    {
    __KTRACE_OPT(KUSB, Kern::Printf("TUsbcAlternateSettingList::~TUsbcAlternateSettingList()"));
    for (TInt i = 0; i <= KMaxEndpointsPerClient; i++)
        {
        delete iEndpoint[i];
        }
    }


TUsbcDeviceStatusQueue::TUsbcDeviceStatusQueue()
    {
    FlushQueue();
    }


void TUsbcDeviceStatusQueue::FlushQueue()
    {
    for (TInt i = 0; i < KUsbDeviceStatusQueueDepth; i++)
        {
        iDeviceStatusQueue[i] = KUsbDeviceStatusNull;
        }
    iStatusQueueHead = 0;
    }


void TUsbcDeviceStatusQueue::AddStatusToQueue(TUint32 aDeviceStatus)
    {
    // Only add a new status if it is not a duplicate of the one at the head of the queue
    if (!(iStatusQueueHead != 0 &&
          iDeviceStatusQueue[iStatusQueueHead - 1] == aDeviceStatus))
        {
        if (iStatusQueueHead == KUsbDeviceStatusQueueDepth)
            {
            // Discard item at tail of queue
            TUint32 status;
            GetDeviceQueuedStatus(status);
            }
        iDeviceStatusQueue[iStatusQueueHead] = aDeviceStatus;
        iStatusQueueHead++;
        }
    }


TInt TUsbcDeviceStatusQueue::GetDeviceQueuedStatus(TUint32& aDeviceStatus)
    {
    TInt r = KErrNone;
    if (iStatusQueueHead <= 0)
        {
        r = KErrGeneral;
        aDeviceStatus = KUsbDeviceStatusNull;
        }
    else
        {
        aDeviceStatus = iDeviceStatusQueue[0];
        for(TInt i = 1; i < KUsbDeviceStatusQueueDepth; i++)
            {
            TUint32 s = iDeviceStatusQueue[i];
            iDeviceStatusQueue[i - 1] = s;
            }
        iStatusQueueHead--;
        iDeviceStatusQueue[KUsbDeviceStatusQueueDepth - 1] = KUsbDeviceStatusNull;
        }
    return r;
    }

void TClientAsynchNotify::Reset()
{
    iBufferRequest->Reset();
    iClientBuffer=NULL;
}

//---