usbclasses/usbphoneasmodem/classimplementation/mscfileserver/src/bulkonlytransport.cpp
changeset 35 9d8b04ca6939
child 63 ef2686f7597e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbclasses/usbphoneasmodem/classimplementation/mscfileserver/src/bulkonlytransport.cpp	Fri Jun 04 10:27:39 2010 +0100
@@ -0,0 +1,1491 @@
+// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// 
+// 
+
+#include "bulkonlytransport.h"
+#include "mscfileserver.h"
+#include "usbmscfileshared.h"
+#include "debug.h"
+#define InEndpoint EEndpoint1
+#define OutEndpoint EEndpoint2
+//This value defined in USB Mass Storage Bulk Only Transrt spec and not supposed to be changed
+LOCAL_D const TInt KRequiredNumberOfEndpoints = 2; // in addition to endpoint 0. 
+
+
+//CBW offsets
+LOCAL_D const TInt KCbwSignatureOffset = 0;
+LOCAL_D const TInt KCbwTagOffset = 4;
+LOCAL_D const TInt KCbwDataTransferLengthOffset = 8;
+LOCAL_D const TInt KCbwFlagOffset = 12;
+LOCAL_D const TInt KCbwLunOffset = 13;
+LOCAL_D const TInt KCbwCbLengthOffset = 14;
+LOCAL_D const TInt KMaxCbwcbLength = 16;
+// CSW offsets
+LOCAL_D const TInt KCswSingnatureOffset = 0;
+LOCAL_D const TInt KCswTagOffset = 4;
+LOCAL_D const TInt KCswDataResidueOffset = 8;
+LOCAL_D const TInt KCswStatusOffset = 12;
+LOCAL_D const TInt KCswLength = 13;
+LOCAL_D const TInt KUsbNumInterfacesOffset = 4;
+
+/**
+ This function unpacks into the TUsbRequestHdr class from a descriptor with 
+ the alignment that would be introduced on the USB bus.
+ 
+ @param aBuffer Input buffer
+ @param aTarget Unpacked header.
+ @return Error.
+ */
+TInt TUsbRequestHdr::Decode(const TDesC8& aBuffer)
+
+    {
+    if (aBuffer.Length() < static_cast<TInt> (KRequestHdrSize))
+        {
+        TRACE_ERROR((_L("TUsbRequestHdr::Decode buffer invalid length %d"),aBuffer.Length()))
+        return KErrGeneral;
+        }
+
+    // Decode as SPEC 1.3.3
+    iRequestType = aBuffer[0];
+    iRequest = static_cast<TEp0Request>(aBuffer[1]);
+    iValue = static_cast<TUint16>(aBuffer[2] + (aBuffer[3] << 8));
+    iIndex = static_cast<TUint16>(aBuffer[4] + (aBuffer[5] << 8));
+    iLength = static_cast<TUint16>(aBuffer[6] + (aBuffer[7] << 8));
+    TRACE_INFO((_L("type=%d request=%d value=%d index=%d length=%d"), iRequestType,iRequest,iValue,iIndex,iLength))
+
+    return KErrNone;
+    }
+
+/**
+ This function determines whether data is required by the host in response 
+ to a message header.
+
+ @return TBool	Flag indicating whether a data response required.
+ */
+TBool TUsbRequestHdr::IsDataResponseRequired() const
+
+    {
+    return (iRequestType & 0x80) ? ETrue : EFalse;
+    }
+
+//
+/**
+ Called by CBulkOnlyTransport to create an instance of CControlInterface
+
+ @param aParent reference to the CBulkOnlyTransport
+ */
+CControlInterface* CControlInterface::NewL(CBulkOnlyTransport& aParent)
+    {
+    CControlInterface* self = new (ELeave) CControlInterface(aParent);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CActiveScheduler::Add(self);
+    CleanupStack::Pop();
+    return self;
+    }
+
+void CControlInterface::ConstructL()
+    {
+    }
+
+/**
+ c'tor
+
+ @param aParent reference to the CBulkOnlyTransport
+ */
+CControlInterface::CControlInterface(CBulkOnlyTransport& aParent) :
+	CActive(EPriorityStandard),
+	iParent(aParent),
+	iCurrentState(ENone)
+    {
+    }
+
+/**
+ d'tor
+ */
+CControlInterface::~CControlInterface()
+    {
+    TRACE_FUNC
+	Cancel();
+    }
+
+/**
+ Called by  CBulkOnlyTransportStart to start control interface
+ */
+TInt CControlInterface::Start()
+    {
+    TRACE_FUNC
+    TInt res = ReadEp0Data();
+    return (res);
+    }
+
+/**
+ Called by CBulkOnlyTransportStart to stop control interface
+ */
+void CControlInterface::Stop()
+    {
+    TRACE_FUNC
+    // Don't need to be any thing if we're not in active state
+    if (!IsActive())
+        {
+        TRACE_INFO((_L("Not active")))
+        return;
+        }
+
+    TRACE_INFO((_L("Stopping...")))
+
+    // Stop by cancel
+    Cancel();
+    iCurrentState = ENone;
+    }
+
+/**
+ Cancel outstanding request (if any)
+ */
+void CControlInterface::DoCancel()
+    {
+    TRACE_FUNC
+    switch(iCurrentState)
+        {
+        case EReadEp0Data:
+        iParent.Ldd().ReadCancel(EEndpoint0);
+        break;
+        case ESendMaxLun:
+        iParent.Ldd().WriteCancel(EEndpoint0);
+        break;
+        default:
+        TRACE_ERROR((_L("\nWrong state !")))
+        __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState));
+        }
+    }
+
+/**
+ Implement CControlInterface state machine
+ */
+void CControlInterface::RunL()
+    {
+    TRACE_FUNC
+    if (iStatus != KErrNone)
+        {
+        TRACE_ERROR(( _L( "Error %d in RunL" ), iStatus.Int() ))
+
+        //read EP0  again 
+        ReadEp0Data();
+        return;
+        }
+
+    switch (iCurrentState)
+        {
+        case ESendMaxLun:
+            ReadEp0Data();
+            break;
+
+        case EReadEp0Data:
+            DecodeEp0Data();
+            break;
+
+        default:
+            TRACE_ERROR(( _L( "error: (Shouldn't end up here...)" ) ))
+            __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState));
+            break;
+        }
+    return;
+    }
+
+/**
+ Post a read request to EEndpoint0 to read request header
+ */
+TInt CControlInterface::ReadEp0Data()
+    {
+    TRACE_FUNC
+    if ( IsActive() )
+        {
+        TRACE_ERROR(( _L( "Still active" ) ))
+        return KErrServerBusy;
+        }
+
+    iParent.Ldd().Read(iStatus, EEndpoint0, iData, KRequestHdrSize);
+
+    iCurrentState = EReadEp0Data;
+
+    SetActive();
+    return KErrNone;
+    }
+
+/**
+ Decode request header and do appropriate action - get max LUN info or post a reset request
+ */
+void CControlInterface::DecodeEp0Data()
+    {
+    TRACE_FUNC
+    if ( IsActive() )
+        {
+        TRACE_ERROR(( _L( "Still active" ) ))
+        __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceStillActive));
+        return;
+        }
+
+    TInt err = iRequestHeader.Decode(iData);
+
+    if (err != KErrNone)
+        {
+        TRACE_WARNING((_L("Decode header error : err=%d"), err))
+        return;
+        }
+
+    switch(iRequestHeader.iRequest)
+        {
+        // GET MAX LUN (0xFE)
+        case TUsbRequestHdr::EReqGetMaxLun:
+            {
+            TRACE_INFO((_L("DecodeEp0Data : 'Get Max LUN' Request MaxLun = %d" ),
+                            iParent.MaxLun() ))
+
+            if ( iRequestHeader.iRequestType != 0xA1 //value from USB MS BOT spec
+                    || iRequestHeader.iIndex> 15 || iRequestHeader.iValue != 0 || iRequestHeader.iLength != 1)
+                {
+                TRACE_ERROR((_L("GetMaxLun command packet check error")))
+                iParent.Ldd().EndpointZeroRequestError();
+                break;
+                }
+
+            iData.FillZ(1); //Return only 1 byte to host 
+            iData[0] = static_cast<TUint8>(iParent.MaxLun()); // Supported Units
+            iParent.Ldd().Write(iStatus, EEndpoint0, iData, 1);
+
+            iCurrentState = ESendMaxLun;
+            SetActive();
+
+            return;
+            }
+
+        // RESET (0xFF)
+        case TUsbRequestHdr::EReqReset:
+            {
+            TRACE_INFO((_L("DecodeEp0Data : 'Mass Storage Reset' Request")))
+
+            if ( iRequestHeader.iRequestType != 0x21 //value from USB MS BOT spec
+                    || iRequestHeader.iIndex> 15 || iRequestHeader.iValue != 0 || iRequestHeader.iLength != 0)
+                {
+                TRACE_ERROR((_L("MSC Reset command packet check error")))
+                iParent.Ldd().EndpointZeroRequestError();
+                break;
+                }
+
+            iParent.HwStop();
+            iParent.Controller().Reset();
+            iParent.HwStart(ETrue);
+
+            err = iParent.Ldd().SendEp0StatusPacket();
+            TRACE_INFO((_L("SendEp0StatusPacket: err=%d"), err))
+
+            return;
+            }
+        // Unknown?
+        default:
+            {
+            TRACE_ERROR((_L("DecodeEp0Data : Unknown Request")))
+            }
+        }
+    ReadEp0Data(); //try to get another request 
+    }
+
+//-------------------------------------
+/**
+ Create CBulkOnlyTransport object
+ @param aNumDrives - The number of drives available for MS
+ @param aController - reference to the parent
+ @return pointer to newly created object
+ */
+CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CMscFileController& aController)
+    {
+	CBulkOnlyTransport* self = new(ELeave) CBulkOnlyTransport(aNumDrives, aController);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+/**
+ c'tor 
+ @param aNumDrives - The number of drives available for MS
+ @param aController - reference to the parent
+ */
+CBulkOnlyTransport::CBulkOnlyTransport(TInt aNumDrives,CMscFileController& aController):
+	CActive(EPriorityStandard),
+	iMaxLun(aNumDrives-1),
+	iController(aController),
+	iReadBuf(NULL,0),
+	iWriteBuf(NULL,0),
+	iStallAllowed(ETrue)
+    {
+    }
+
+/**
+ Constructs the CBulkOnlyTranspor object
+ */
+void CBulkOnlyTransport::ConstructL()
+    {
+    TRACE_FUNC
+    iControlInterface = CControlInterface::NewL(*this);
+    iDeviceStateNotifier = CActiveDeviceStateNotifier::NewL(*this);
+    CActiveScheduler::Add(this);
+    }
+
+/**
+ Destructor
+ */
+CBulkOnlyTransport::~CBulkOnlyTransport()
+    {
+    TRACE_FUNC
+    if (iInterfaceConfigured)
+        {
+        Stop();
+        }
+    delete iControlInterface;
+    delete iDeviceStateNotifier;
+    }
+
+/**
+ Set or unset configuration descriptor for USB MassStorage Bulk Only transport
+
+ @param aUnset indicate whether set or unset descriptor
+ @return KErrNone if operation was completed successfully, errorcode otherwise
+ */
+TInt CBulkOnlyTransport::SetupConfigurationDescriptor(TBool aUnset)
+    {
+    TRACE_FUNC
+    TInt ret(KErrNone);
+    TInt configDescriptorSize(0);
+
+    iLdd.GetConfigurationDescriptorSize(configDescriptorSize);
+    if (static_cast<TUint> (configDescriptorSize) != KUsbDescSize_Config)
+        {
+        return KErrCorrupt;
+        }
+
+    TBuf8<KUsbDescSize_Config> configDescriptor;
+    ret = iLdd.GetConfigurationDescriptor(configDescriptor);
+    if (ret != KErrNone)
+        {
+        return ret;
+        }
+
+    // I beleive that other fields setted up during LDD initialisation
+    if (aUnset)
+        {
+        --configDescriptor[KUsbNumInterfacesOffset];
+        }
+    else
+        {
+        ++configDescriptor[KUsbNumInterfacesOffset];
+        }
+    ret = iLdd.SetConfigurationDescriptor(configDescriptor);
+
+    return ret;
+    }
+
+/**
+ Set up interface descriptor
+
+ @return KErrNone if operation was completed successfully, errorcode otherwise
+ */
+TInt CBulkOnlyTransport::SetupInterfaceDescriptors()
+    {
+    TRACE_FUNC
+    // Device caps
+    TUsbDeviceCaps d_caps;
+    TInt ret = iLdd.DeviceCaps(d_caps);
+    if (ret != KErrNone)
+        {
+        return ret;
+        }
+    TInt totalEndpoints = d_caps().iTotalEndpoints;
+    if (totalEndpoints < KRequiredNumberOfEndpoints)
+        {
+        return KErrHardwareNotAvailable;
+        }
+
+    // Endpoint caps
+    TUsbcEndpointData data[KUsbcMaxEndpoints];
+	TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
+    ret = iLdd.EndpointCaps(dataptr);
+    if (ret != KErrNone)
+        {
+        return ret;
+        }
+
+    // Set the active interface
+    TUsbcInterfaceInfoBuf ifc;
+    TInt ep_found = 0;
+    TBool foundBulkIN = EFalse;
+    TBool foundBulkOUT = EFalse;
+
+    for (TInt i = 0; i < totalEndpoints; i++)
+        {
+        const TUsbcEndpointCaps* caps = &data[i].iCaps;
+        const TInt maxPacketSize = caps->MaxPacketSize();
+		if (!foundBulkIN &&
+			(caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirIn)) == (KUsbEpTypeBulk | KUsbEpDirIn))
+            {
+            // InEndpoint is going to be our TX (IN, write) endpoint
+            ifc().iEndpointData[0].iType = KUsbEpTypeBulk;
+            ifc().iEndpointData[0].iDir = KUsbEpDirIn;
+            ifc().iEndpointData[0].iSize = maxPacketSize;
+            ifc().iEndpointData[0].iInterval_Hs = 0;
+			ifc().iEndpointData[0].iFeatureWord1 = KUsbcEndpointInfoFeatureWord1_DMA;
+            foundBulkIN = ETrue;
+            if (++ep_found == KRequiredNumberOfEndpoints)
+                {
+                break;
+                }
+            continue;
+            }
+		if (!foundBulkOUT &&
+			(caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirOut)) == (KUsbEpTypeBulk | KUsbEpDirOut))
+            {
+            // OutEndpoint is going to be our RX (OUT, read) endpoint
+            ifc().iEndpointData[1].iType = KUsbEpTypeBulk;
+            ifc().iEndpointData[1].iDir = KUsbEpDirOut;
+            ifc().iEndpointData[1].iSize = maxPacketSize;
+            ifc().iEndpointData[1].iInterval_Hs = 0;
+			ifc().iEndpointData[1].iFeatureWord1 = KUsbcEndpointInfoFeatureWord1_DMA;
+            foundBulkOUT = ETrue;
+            if (++ep_found == KRequiredNumberOfEndpoints)
+                {
+                break;
+                }
+            continue;
+            }
+        }
+    if (ep_found != KRequiredNumberOfEndpoints)
+        {
+        return KErrHardwareNotAvailable;
+        }
+    _LIT16(string, "USB Mass Storage Interface");
+    ifc().iString = const_cast<TDesC16*> (&string);
+    ifc().iTotalEndpointsUsed = KRequiredNumberOfEndpoints;
+    ifc().iClass.iClassNum = 0x08; // Mass Storage
+    ifc().iClass.iSubClassNum = 0x06; // SCSI Transparent Command Set
+    ifc().iClass.iProtocolNum = 0x50; // Bulk Only Transport
+
+	TUint bandwidth_priority = (EUsbcBandwidthOUTDefault | EUsbcBandwidthINDefault);
+    if (d_caps().iHighSpeed)
+        {
+        // If this device supports USB High-speed, then we request 64KB buffers
+        // (otherwise the default 4KB ones will do).
+        bandwidth_priority = (EUsbcBandwidthOUTPlus2 | EUsbcBandwidthINPlus2);
+        // Also, tell the Protocol about it, because it might want to do some
+        // optimizing too.
+        iProtocol->ReportHighSpeedDevice();
+        }
+    ret = iLdd.SetInterface(0, ifc, bandwidth_priority);
+    return ret;
+    }
+
+/**
+ Called by the protocol after processing the packet to indicate that more data is required.  
+
+ @param aData reference to the data buffer. 
+ */
+void CBulkOnlyTransport::SetupReadData(TPtr8& aData)
+    {
+    TRACE_FUNC
+    TRACE_INFO((_L("Length = %d  (bytes)"), aData.Length()))
+    iReadBuf.Set(aData);
+    iReadSetUp = ETrue;
+    }
+
+/**
+ Called by the protocol after processing the packet to indicate that data should be written to the host.  
+
+ @param aData reference to the data buffer. 
+ */
+void CBulkOnlyTransport::SetupWriteData(TPtrC8& aData)
+    {
+    TRACE_FUNC
+    TRACE_INFO((_L("Length = %d  (bytes)"), aData.Length()))
+    iWriteBuf.Set(aData);
+    iWriteSetUp = ETrue;
+    }
+
+TInt CBulkOnlyTransport::Start()
+    {
+    TRACE_FUNC_ENTRY
+
+    TInt err = KErrNone;
+
+    if (!iProtocol)
+        {
+        return KErrBadHandle; //protocol should be set up before start
+        }
+
+    if (IsActive())
+        {
+        TRACE_ERROR((_L("Active before start!")))
+        return KErrInUse;
+        }
+
+    if ((err = iLdd.Open(0)) != KErrNone )
+        {
+        TRACE_ERROR((_L("Error during open ldd!")))
+        return err;
+        }
+
+    if ((err = SetupConfigurationDescriptor()) != KErrNone ||
+            (err = SetupInterfaceDescriptors()) != KErrNone )
+        {
+        iLdd.Close();
+        TRACE_ERROR((_L("Error during descriptors setup!")))
+        return err;
+        }
+
+    iDeviceStateNotifier->Activate(); // activate notifier wich will wait until USB became configured
+    TUsbcDeviceState deviceStatus = EUsbcDeviceStateDefault;
+    err = iLdd.DeviceStatus(deviceStatus);
+    TRACE_INFO((_L("Device status = %d"), deviceStatus))
+    if (err == KErrNone && deviceStatus == EUsbcDeviceStateConfigured)
+        {
+        TRACE_INFO(_L("Starting bulk only transport\n"));
+        err = HwStart();
+        }
+    iInterfaceConfigured = ETrue;
+    TRACE_FUNC_EXIT
+    return err;
+    }
+
+TInt CBulkOnlyTransport::HwStart(TBool aDiscard)
+    {
+    TRACE_FUNC_ENTRY
+
+    TInt res = iControlInterface->Start();
+
+    iCurrentState = ENone;
+    iWriteSetUp = EFalse;
+    iReadSetUp = EFalse;
+    iStarted = ETrue;
+
+    if (aDiscard)
+        {
+        TInt bytes;
+        const TInt err = iLdd.QueryReceiveBuffer(OutEndpoint, bytes);
+        if (err != KErrNone || bytes <= 0)
+            {
+            TRACE_ERROR((_L("Error: err=%d bytes=%d"), bytes))
+            }
+        else
+            {
+            TRACE_ERROR((_L("RxBuffer has %d bytes"), bytes))
+            ReadAndDiscardData(bytes);
+            }
+        }
+
+    ReadCBW();
+    TRACE_FUNC_EXIT
+    return res;
+    }
+
+TInt CBulkOnlyTransport::HwStop()
+    {
+    TRACE_FUNC
+
+    if (iStarted)
+        {
+        Cancel();
+        iControlInterface->Cancel();
+        iProtocol->Cancel();
+        iStarted = EFalse;
+        }
+    return KErrNone;
+    }
+
+TInt CBulkOnlyTransport::HwSuspend()
+    {
+    TRACE_FUNC
+    return KErrNone;
+    }
+
+TInt CBulkOnlyTransport::HwResume()
+    {
+    TRACE_FUNC
+    return KErrNone;
+    }
+
+/**
+ Stops the Bulk Only Transport
+ */
+TInt CBulkOnlyTransport::Stop()
+    {
+    TRACE_FUNC
+    iControlInterface->Cancel();
+    iDeviceStateNotifier->Cancel();
+    Cancel();
+    if (iInterfaceConfigured)
+        {
+        iLdd.ReleaseInterface(0);
+        SetupConfigurationDescriptor(ETrue);
+        iLdd.Close();
+        }
+    iCurrentState = ENone;
+    iInterfaceConfigured = EFalse;
+
+    return KErrNone;
+    }
+
+/**
+ Read aLength bytes of data from the host into the read buffer.
+ @param aLength The number of bytes to read from the host.
+ */
+void CBulkOnlyTransport::ReadCBW()
+    {
+    TRACE_FUNC
+    if (IsActive())
+        {
+        TRACE_ERROR(( _L( "Still active" ) ))
+        __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+        return;
+        }
+
+    iCbwBuf.SetMax();
+    iLdd.ReadUntilShort(iStatus, OutEndpoint, iCbwBuf, iCbwBuf.Length());
+
+    iCurrentState = EWaitForCBW;
+    SetActive();
+    }
+
+void CBulkOnlyTransport::DoCancel()
+    {
+    TRACE_FUNC
+    iLdd.WriteCancel(InEndpoint);
+    iLdd.ReadCancel(OutEndpoint);
+    }
+
+void CBulkOnlyTransport::Activate(TInt aReason)
+    {
+    SetActive();
+    TRequestStatus* r = &iStatus;
+    User::RequestComplete(r, aReason);
+    }
+
+void CBulkOnlyTransport::RunL()
+    {
+    TRACE_FUNC
+    if (iStatus != KErrNone)
+        {
+        TRACE_ERROR((_L("Error %d in RunL, halt endpoints \n"), iStatus.Int()))
+        SetPermError(); //halt endpoints for reset recovery
+        return;
+        }
+
+    switch (iCurrentState)
+        {
+        case EWaitForCBW:
+            TRACE_INFO((_L("EWaitForCBW")))
+            DecodeCBW();
+            break;
+
+        case EWritingData:
+            TRACE_INFO((_L("EWritingData")))
+            iWriteSetUp = EFalse; //the buffer was used
+
+            if (iDataResidue && iStallAllowed)
+                {
+                StallEndpointAndWaitForClear(InEndpoint);
+                }
+
+            SendCSW(iCbwTag, iDataResidue, iCmdStatus);
+            break;
+
+        case EReadingData:
+            {
+            TRACE_INFO((_L("EReadingData")))
+
+            TInt ret = KErrNone;
+            FOREVER
+                {
+                if (iReadSetUp)
+                    {
+                    ret = iProtocol->ReadComplete(KErrNone);
+                    }
+
+                TUint deviceDataLength = static_cast<TUint>(iReadBuf.Length());
+                if(ret == KErrCompletion)
+                    {
+                    // The protocol has indicated with KErrCompletion that sufficient
+                    // data is available in the buffer to process the transfer immediately.
+                    iDataResidue -= deviceDataLength;
+                    iLdd.Read(iStatus, OutEndpoint, iReadBuf, deviceDataLength);
+                    User::WaitForRequest(iStatus);
+                    if (iStatus != KErrNone)
+                        {
+                        // An error occurred - halt endpoints for reset recovery
+                        TRACE_ERROR((_L("Error %d in EReadingData, halt endpoints"),
+                                        iStatus.Int()))
+                        SetPermError();
+                        return;
+                        }
+                    }
+                else if(ret == KErrNotReady)
+                    {
+                    // The protocol has indicated with KErrNotReady that insufficient
+                    // data is available in the buffer, so should wait for it to arrive
+                    ReadData(deviceDataLength);
+                    break;
+                    }
+                else
+                    {
+                    // The protocol has indicated that transfer is 
+                    // complete, so send the CSW response to the host.
+                    iReadSetUp = EFalse;
+
+                    if (ret != KErrNone)
+                        {
+                        iCmdStatus = ECommandFailed;
+                        }
+
+                    if (iDataResidue)
+                        {
+                        TRACE_INFO((_L("Discarding residue")))
+                        // we have to read as much data as available that host PC sends;
+                        // otherwise, bulk-out endpoint will need to keep sending NAK back.
+                        ReadAndDiscardData(iDataResidue);
+                        }
+                    SendCSW(iCbwTag, iDataResidue, iCmdStatus);
+                    break;
+                    }
+                }
+            }
+        break;
+
+        case ESendingCSW:
+        TRACE_INFO((_L("ESendingCSW")))
+        ReadCBW();
+        break;
+
+        case EPermErr:
+        TRACE_INFO((_L("EPermErr")))
+        StallEndpointAndWaitForClear(InEndpoint);
+        break;
+
+        default:
+        SetPermError(); // unexpected state
+        }
+    }
+
+/**
+ Prepare incase we need to read data from host
+ Called in DecodeCBW(...)
+ @param aHostDataLength The number of bytes to read from the host.
+ */
+void CBulkOnlyTransport::PrepareReadFromHost(TUint aHostDataLength)
+    {
+    if (!iReadSetUp)
+        {
+			iDataResidue =aHostDataLength;
+			TRACE_INFO((_L("Read buffer was not setup\n")))
+            //Use next block instead of StallEndpointAndWaitForClear(OutEndpoint); 
+            {
+            iBuf.SetLength(KBOTMaxBufSize);
+            TUint c =0;
+            TRequestStatus status;
+            while (c<aHostDataLength)
+                {
+                TInt len;
+                if (aHostDataLength - c> KBOTMaxBufSize)
+                    {
+                    len = KBOTMaxBufSize;
+                    }
+                else
+                    {
+                    len = aHostDataLength - c;
+                    }
+
+                iLdd.Read(status, OutEndpoint, iBuf, len);
+                User::WaitForRequest(status);
+                c += KBOTMaxBufSize;
+                }
+            }
+
+        if (iWriteSetUp) //case (10)
+            {
+            TRACE_INFO((_L("case 10\n")))
+            SendCSW(iCbwTag, aHostDataLength, EPhaseError);
+            }
+        else // case (9)
+
+            {
+            TRACE_INFO((_L("Case 9\n")))
+            SendCSW(iCbwTag, aHostDataLength, iCmdStatus);
+            }
+
+        return;
+        }
+    else
+        {
+        TUint deviceDataLength = static_cast<TUint>(iReadBuf.Length());
+        iDataResidue =aHostDataLength - deviceDataLength;
+        TRACE_INFO((_L("deviceDataLength=%d, DataResidue (read from host) =%d\n"),
+                        deviceDataLength,iDataResidue))
+
+        if (deviceDataLength <= aHostDataLength) // case (11) and (12)
+
+            {
+            TRACE_INFO((_L("Case 11 or 12\n")))
+            ReadData(deviceDataLength);
+            return;
+            }
+
+        if (deviceDataLength> aHostDataLength) // case  (13)
+
+            {
+            TRACE_INFO((_L("Case 13\n")))
+            /**
+             * Comment following line in order to pass compliant test.
+             * As spec said in case 13:"The device may receive data up to a
+             * total of dCBWDataTransferLength."
+             * Here we choose to ignore incoming data.
+             */
+            //StallEndpointAndWaitForClear(OutEndpoint); //Stall Out endpoint
+            if (iReadSetUp)
+                {
+                iLdd.Read(iStatus, OutEndpoint, iReadBuf, aHostDataLength);
+                User::WaitForRequest(iStatus);
+                iProtocol->ReadComplete(KErrGeneral);
+                iReadSetUp = EFalse;
+                }
+            SendCSW(iCbwTag, aHostDataLength, EPhaseError);
+            return;
+            }
+        }
+    }
+
+/**
+ Prepare incase we need to read data from host
+ Called in DecodeCBW(...)
+ @param aHostDataLength The number of bytes to write to the host.
+ */
+void CBulkOnlyTransport::PrepareWriteToHost(TUint aHostDataLength)
+    {
+    if (!iWriteSetUp) //write buffer was not set up 
+        {
+        TRACE_INFO((_L("Write buffer was not setup")))
+        iDataResidue =aHostDataLength;
+        TRACE_INFO((_L("DataResidue (write to host)=%d"),iDataResidue))
+
+        //------------------------------------
+        if (aHostDataLength <= KBOTMaxBufSize)
+            {
+            TRACE_INFO((_L("Case 4 or 8\n")))
+            iBuf.FillZ(aHostDataLength);
+            iLdd.Write(iStatus, InEndpoint, iBuf, aHostDataLength);
+            SetActive();
+            iCurrentState = EWritingData;
+            iStallAllowed = EFalse;
+            if (iReadSetUp) //read buffer WAS set up - case (8)
+
+                {
+                TRACE_INFO((_L("It is Case 8")))
+                iCmdStatus = EPhaseError;
+                }
+            return;
+            }
+        else
+        //------------------------------------
+        //					Use next block instead of StallEndpointAndWaitForClear(InEndpoint);
+
+            {
+            iBuf.FillZ(KBOTMaxBufSize);
+            TUint c =0;
+            TRequestStatus status;
+            while (c<aHostDataLength)
+                {
+                TInt len;
+                if (aHostDataLength - c> KBOTMaxBufSize)
+                    {
+                    len = KBOTMaxBufSize;
+                    }
+                else
+                    {
+                    len = aHostDataLength - c;
+                    }
+
+                iLdd.Write(status, InEndpoint, iBuf, len);
+                User::WaitForRequest(status);
+                c += KBOTMaxBufSize;
+                }
+            }
+
+        if (iReadSetUp) //read buffer WAS set up - case (8)
+            {
+            TRACE_INFO(_L("Case 8"));
+            SendCSW(iCbwTag, aHostDataLength, EPhaseError);
+            //don't care to reset any flag - should get reset recovery
+            }
+        else // case (4)
+            {
+            TRACE_INFO((_L("Case 4")))
+            SendCSW(iCbwTag, aHostDataLength, iCmdStatus);
+            }
+        return;
+        }
+    else
+        {
+        //================== 
+        TUint deviceDataLength = static_cast<TUint>(iWriteBuf.Length());
+        iDataResidue =aHostDataLength - deviceDataLength;
+        TRACE_INFO((_L("Device data length = %d, DataResidue (write to host)=%d"),
+                        deviceDataLength, iDataResidue))
+
+        if (deviceDataLength < aHostDataLength &&
+                aHostDataLength < KBOTMaxBufSize )
+            {
+            TRACE_INFO((_L("Case 5 (padding)\n")))
+            iBuf.Zero();
+            iBuf.Append(iWriteBuf);
+            iBuf.SetLength(aHostDataLength);
+            iStallAllowed = EFalse;
+            TRACE_INFO((_L("iBuf.Length=%d\n"),iBuf.Length()))
+            iLdd.Write(iStatus, InEndpoint, iBuf, aHostDataLength);
+            SetActive();
+            iCurrentState = EWritingData;
+            return;
+            }
+
+        //===================
+
+        if (deviceDataLength == aHostDataLength) //case (6)[==]
+
+            {
+            TRACE_INFO((_L("Case 6\n")))
+            WriteData(deviceDataLength);
+            return;
+            }
+        else if (deviceDataLength < aHostDataLength) //case (5)[<]
+
+            {
+            TRACE_INFO((_L("Case 5\n")))
+            WriteData(deviceDataLength, ETrue); // Send ZLP
+            return;
+            }
+        else // deviceDataLength > aHostDataLength - case (7)
+
+            {
+            TRACE_INFO((_L("Case 7\n")))
+            iCmdStatus = EPhaseError;
+            iDataResidue = 0;
+            WriteData(aHostDataLength);
+            return;
+            }
+        }
+    }
+
+/**
+ Decode the CBW received from the host via OutEndpoint
+
+ - If the header is valid, the data content is passed to the parser.
+ - Depending on the command, more data may be transmitted/received.
+ - ...or the CSW is sent (if not a data command).
+
+ */
+void CBulkOnlyTransport::DecodeCBW()
+    {
+    TRACE_FUNC
+    if (!CheckCBW()) //check if CBW valid and meaningful
+
+        {
+        // CBW not valid or meaningful
+        // Specification says: "If the CBW is not valid, the device shall STALL
+        // the Bulk-In pipe. Also, the device shall either STALL the Bulk-Out pipe,
+        // or the device shall accept and discard any Bulk-Out data. The device
+        // shall maintain this state until a Reset Recovery."
+        // Here we keep bulk-in ep stalled and ignore bulk-out ep.
+        SetPermError();
+        return;
+        }
+
+    TPtrC8 aData;
+    aData.Set(&iCbwBuf[KCbwCbLengthOffset], KMaxCbwcbLength + 1); //prepare data for protocol starting form Length 
+    TUint8 lun = static_cast<TUint8> (iCbwBuf[13] & 0x0f);
+
+	iCbwTag  =	static_cast<TUint32>(iCbwBuf[KCbwTagOffset])		| 
+				static_cast<TUint32>(iCbwBuf[KCbwTagOffset+1])	<<8 | 
+				static_cast<TUint32>(iCbwBuf[KCbwTagOffset+2])	<<16| 
+				static_cast<TUint32>(iCbwBuf[KCbwTagOffset+3])	<<24;
+
+    TInt i = KCbwDataTransferLengthOffset;
+	TUint hostDataLength = 	static_cast<TUint32>(iCbwBuf[i  ])		| 
+							static_cast<TUint32>(iCbwBuf[i+1]) <<8 	| 
+							static_cast<TUint32>(iCbwBuf[i+2]) <<16	| 
+							static_cast<TUint32>(iCbwBuf[i+3]) <<24;
+
+    TBool dataToHost = iCbwBuf[KCbwFlagOffset] & 0x80;
+
+    TRACE_INFO((_L("lun =%d, hostDataLength=%d, CBWtag = 0x%X\n, dataToHost=%d"),
+                    lun, hostDataLength, iCbwTag, dataToHost))
+    //
+    TBool ret = iProtocol->DecodePacket(aData, lun);
+    //
+
+    iStallAllowed = ETrue;
+
+    if (!ret)
+        {
+        TRACE_INFO((_L("Command Failed")))
+        iCmdStatus = ECommandFailed;
+        }
+    else
+        {
+        TRACE_INFO((_L("Command Passed")))
+        iCmdStatus = ECommandPassed;
+        }
+
+    if (hostDataLength == 0)
+        {
+        TRACE_INFO((_L("No data transfer expected\n")))
+        iDataResidue = 0;
+        if (iWriteSetUp || iReadSetUp) // case (2) and (3)
+
+            {
+            TRACE_INFO((_L("Case 2 or 3\n")))
+            SendCSW(iCbwTag, 0, EPhaseError);
+            }
+        else
+            {
+            TRACE_INFO((_L("Case 1\n")))
+            SendCSW(iCbwTag, 0, iCmdStatus); //case (1)
+            }
+
+        return;
+        }
+    else
+        {
+        // Data Direction, To or From Host
+        if (dataToHost)
+            {
+            PrepareWriteToHost(hostDataLength);
+            }
+        else
+            {
+            PrepareReadFromHost(hostDataLength);
+            }
+        }
+    }
+
+/**
+ Check if CBW Valid and Meaningful.  
+
+ @return ETrue if CBW is Valid and Meaningful, EFalse otherwise
+ */
+TBool CBulkOnlyTransport::CheckCBW()
+    {
+    TRACE_FUNC
+
+    // Check valid
+
+    // Check length
+    if (iCbwBuf.Length() != KCbwLength)
+        {
+        TRACE_INFO((_L("Bad length: %d"), iCbwBuf.Length()))
+        return EFalse;
+        }
+
+    // Check signature
+    TInt i = KCbwSignatureOffset;
+	if (iCbwBuf[i  ] != 0x55 ||         // CBW Singature from USB Bulk-Only Transport spec
+		iCbwBuf[i+1] != 0x53 ||
+		iCbwBuf[i+2] != 0x42 ||
+		iCbwBuf[i+3] != 0x43)
+        {
+        TRACE_INFO((_L("Bad signature")))
+        TRACE_INFO((_L(" 0x%x, 0x%x, 0x%x, 0x%x"),
+                        iCbwBuf[i], iCbwBuf[i+1], iCbwBuf[i+2],iCbwBuf[i+3]))
+        return EFalse;
+        }
+
+    // Check meaningful
+
+    // Check reserved bits ( must be zero )
+    if ((iCbwBuf[KCbwLunOffset] & 0xF0) || (iCbwBuf[KCbwCbLengthOffset] & 0xE0))
+        {
+        TRACE_INFO((_L("Reserved bits not zero\n")))
+        return EFalse;
+        }
+
+    // check command block length
+    TInt cbwcbLength = iCbwBuf[KCbwCbLengthOffset] & 0x1F;
+    if (cbwcbLength>KMaxCbwcbLength)
+        {
+        TRACE_INFO((_L("Incorrect block length\n")))
+        return EFalse;
+        }
+
+    //check LUN
+    TInt8 lun = static_cast<TUint8>(iCbwBuf[KCbwLunOffset] & 0x0f);
+    if (iMaxLun < lun)
+        {
+        TRACE_INFO((_L("bad lun: %d"), lun))
+        return EFalse;
+        }
+
+    return ETrue;
+    }
+
+/**
+ Initiate stalling of bulk IN endpoint.
+ Used when protocol wants to force host to initiate a reset recovery.
+ */
+void CBulkOnlyTransport::SetPermError()
+    {
+    TRACE_FUNC
+    iCurrentState = EPermErr;
+    Activate(KErrNone);
+    }
+
+/**
+ Send data provided by protocol to the host
+
+ @param aLength amount of data (in bytes) to be send to host
+ */
+void CBulkOnlyTransport::WriteData(TUint aLength, TBool aZlpRequired)
+    {
+    TRACE_FUNC
+
+    if (IsActive())
+        {
+        TRACE_INFO((_L("Still active")))
+        __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+        return;
+        }
+    iLdd.Write(iStatus, InEndpoint, iWriteBuf, aLength, aZlpRequired);
+    iCurrentState = EWritingData;
+    SetActive();
+    }
+
+/**
+ Request data form the host for the protocol
+
+ @param aLength amount of data (in bytes) to be received from the host
+ */
+void CBulkOnlyTransport::ReadData(TUint aLength)
+    {
+    TRACE_FUNC
+    if (IsActive())
+        {
+        TRACE_INFO((_L("Still active")))
+        __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+        return;
+        }
+    iLdd.Read(iStatus, OutEndpoint, iReadBuf, aLength);
+    SetActive();
+    iCurrentState = EReadingData;
+    }
+
+/**
+ Send Command Status Wrapper to the host
+
+ @param aTag Echo of Command Block Tag sent by the host.
+ @param aDataResidue the difference between the amount of data expected by the
+ host, and the actual amount of data processed by the device.
+ @param aStatus indicates the success or failure of the command.
+ */
+void CBulkOnlyTransport::SendCSW(TUint aTag, TUint aDataResidue, TCswStatus aStatus)
+    {
+    TRACE_FUNC
+    TRACE_INFO((_L("DataResidue = %d, Status = %d \n"), aDataResidue, aStatus))
+
+    if (IsActive())
+        {
+        TRACE_INFO((_L("Still active")))
+        __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+        return;
+        }
+    TBuf8<KCswLength> csw(KCswLength);
+
+    TInt i = KCswSingnatureOffset;
+    csw[i] = 0x55; // CSW Singature from USB Bulk-Only Transport spec
+    csw[i + 1] = 0x53;
+    csw[i + 2] = 0x42;
+    csw[i + 3] = 0x53;
+
+    i = KCswTagOffset;
+
+    csw[i] = static_cast<TUint8> ((aTag & 0x000000FF));
+    csw[i + 1] = static_cast<TUint8> ((aTag & 0x0000FF00) >> 8);
+    csw[i + 2] = static_cast<TUint8> ((aTag & 0x00FF0000) >> 16);
+    csw[i + 3] = static_cast<TUint8> ((aTag & 0xFF000000) >> 24);
+
+    i = KCswDataResidueOffset;
+    csw[i] = static_cast<TUint8> ((aDataResidue & 0x000000FF));
+    csw[i + 1] = static_cast<TUint8> ((aDataResidue & 0x0000FF00) >> 8);
+    csw[i + 2] = static_cast<TUint8> ((aDataResidue & 0x00FF0000) >> 16);
+    csw[i + 3] = static_cast<TUint8> ((aDataResidue & 0xFF000000) >> 24);
+
+    csw[KCswStatusOffset] = static_cast<TUint8> (aStatus);
+
+    iLdd.Write(iStatus, InEndpoint, csw, KCswLength);
+
+    iCurrentState = ESendingCSW;
+
+    SetActive();
+    }
+
+/**
+ Associates the transport with the protocol.  Called during initialization of the controller.
+
+ @param aProtocol reference to the protocol
+ */
+void CBulkOnlyTransport::RegisterProtocol(MProtocolBase& aProtocol)
+    {
+    TRACE_FUNC
+    iProtocol = &aProtocol;
+    }
+
+/**
+ Used by CControlInterface
+
+ @return reference to the controller which instantiate the CBulkOnlyTransport
+ */
+CMscFileController& CBulkOnlyTransport::Controller()
+    {
+    return iController;
+    }
+
+/**
+ @return the number of logical units supported by the device. 
+ Logical Unit Numbers on the device shall be numbered contiguously starting from LUN
+ 0 to a maximum LUN of 15 (Fh).
+ */
+TInt CBulkOnlyTransport::MaxLun()
+    {
+    return iMaxLun;
+    }
+
+/**
+ Used by CControlInterface
+ @return reference to USB logical driver
+ */
+RDevUsbcClient& CBulkOnlyTransport::Ldd()
+    {
+    return iLdd;
+    }
+
+
+void CBulkOnlyTransport::StallEndpointAndWaitForClear(TEndpointNumber aEndpoint)
+    {
+    TRACE_FUNC
+    __ASSERT_DEBUG(aEndpoint != EEndpoint0, User::Panic(KUsbMsSvrPncCat, EMsWrongEndpoint));
+
+    // Now stall this endpoint
+    TRACE_INFO((_L("Stalling endpoint %d"), aEndpoint))
+    TInt r = iLdd.HaltEndpoint(aEndpoint);
+    if (r != KErrNone)
+        {
+        TRACE_ERROR((_L("Error: stalling ep %d failed: %d"), aEndpoint, r))
+        }
+    TEndpointState ep_state;
+    TInt i = 0;
+    do
+        {
+        // Wait for 10ms before checking the ep status
+        User::After(10000);
+        iLdd.EndpointStatus(aEndpoint, ep_state);
+        if (++i >= 1000)
+            {
+            // 10 secs should be enough
+            TRACE_ERROR((_L("Error: Checked for ep %d de-stall %d seconds - giving up now..."),
+                            aEndpoint, i / 100))
+            // We can only hope for a Reset Recovery
+            return;
+            }
+        }while ((ep_state == EEndpointStateStalled) && iStarted);
+    TRACE_INFO((_L("Checked for ep %d de-stall: %d time(s)"), aEndpoint, i))
+    }
+
+/**
+ * Read out rest data from OutEndpoint and discard them
+ */
+void CBulkOnlyTransport::ReadAndDiscardData(TInt aBytes)
+    {
+    TRACE_FUNC
+    const TUint bufsize = static_cast<TUint>(iReadBuf.Length());
+    __ASSERT_ALWAYS(bufsize> 0, User::Panic(_L("Buffer size is zero"), bufsize));
+    TRequestStatus status;
+    while (aBytes> 0)
+        {
+        TRACE_INFO((_L("Bytes still to be read: %d\n"), aBytes))
+        iLdd.ReadOneOrMore(status, OutEndpoint, iReadBuf, bufsize);
+        User::WaitForRequest(status);
+        TInt err = status.Int();
+        if (err != KErrNone)
+            {
+            // Bad.
+            break;
+            }
+        aBytes -= iReadBuf.Length();
+        }
+    iReadBuf.SetLength(bufsize);
+    }
+
+/**
+ Called by the protocol to determine how many bytes of data are available in the read buffer. 
+
+ @return The number of bytes available in the read buffer
+ */
+TInt CBulkOnlyTransport::BytesAvailable()
+    {
+    TInt bytes = 0;
+    TInt err = iLdd.QueryReceiveBuffer(OutEndpoint, bytes);
+    if (err != KErrNone)
+        bytes = 0;
+    return bytes;
+    }
+
+//
+// --- class CActiveDeviceStateNotifier ---------------------------------------------------------
+//
+CActiveDeviceStateNotifier::CActiveDeviceStateNotifier(CBulkOnlyTransport& aParent)
+/**
+ *
+ */
+	: CActive(EPriorityStandard),
+	  iParent(aParent),
+	  iDeviceState(EUsbcNoState),
+            iOldDeviceState(EUsbcNoState)
+    {
+
+    }
+
+
+CActiveDeviceStateNotifier* CActiveDeviceStateNotifier::NewL(CBulkOnlyTransport& aParent)
+/**
+ *
+ */
+    {
+	CActiveDeviceStateNotifier* self = new (ELeave) CActiveDeviceStateNotifier(aParent);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CActiveScheduler::Add(self);
+    CleanupStack::Pop(); // self
+    return (self);
+    }
+
+void CActiveDeviceStateNotifier::ConstructL()
+/**
+ *
+ */
+    {
+    TRACE_FUNC
+	}
+
+CActiveDeviceStateNotifier::~CActiveDeviceStateNotifier()
+/**
+ *
+ */
+    {
+    TRACE_FUNC
+    Cancel();												// base class
+    }
+
+void CActiveDeviceStateNotifier::DoCancel()
+/**
+ *
+ */
+    {
+    TRACE_FUNC
+    iParent.Ldd().AlternateDeviceStatusNotifyCancel();
+    }
+
+void CActiveDeviceStateNotifier::RunL()
+/**
+ *
+ */
+    {
+    TRACE_FUNC
+    // This displays the device state.
+    // In a real world program, the user could take here appropriate action (cancel a
+    // transfer request or whatever).
+    if (!(iDeviceState & KUsbAlternateSetting))
+        {
+
+        switch (iDeviceState)
+            {
+            case EUsbcDeviceStateUndefined:
+            TRACE_INFO((_L("Device State notifier: Undefined\n")))
+            iParent.HwStop();
+            break;
+            case EUsbcDeviceStateAttached:
+            TRACE_INFO((_L("Device State notifier: Attached\n")))
+            iParent.HwStop();
+            break;
+            case EUsbcDeviceStatePowered:
+            TRACE_INFO((_L("Device State notifier: Powered\n")))
+            iParent.HwStop();
+            break;
+            case EUsbcDeviceStateDefault:
+            TRACE_INFO((_L("Device State notifier: Default\n")))
+            iParent.HwStop();
+            break;
+            case EUsbcDeviceStateAddress:
+            TRACE_INFO((_L("Device State notifier: Address\n")))
+            iParent.HwStop();
+            break;
+            case EUsbcDeviceStateConfigured:
+            TRACE_INFO((_L("Device State notifier: Configured\n")))
+            if (iOldDeviceState == EUsbcDeviceStateSuspended)
+                {
+                iParent.HwResume();
+                }
+            else
+                {
+                iParent.HwStart();
+                }
+            break;
+            case EUsbcDeviceStateSuspended:
+            TRACE_INFO((_L("Device State notifier: Suspended\n")))
+            if (iOldDeviceState == EUsbcDeviceStateConfigured)
+                {
+                iParent.HwSuspend();
+                }
+            break;
+            default:
+            TRACE_INFO((_L("Device State notifier: ***BAD***\n")))
+            iParent.HwStop();
+            break;
+            }
+        iOldDeviceState = iDeviceState;
+        }
+    else if (iDeviceState & KUsbAlternateSetting)
+        {
+        TRACE_INFO((_L("Device State notifier: Alternate interface setting has changed: now %d\n"),
+                        iDeviceState & ~KUsbAlternateSetting))
+        }
+    Activate();
+    }
+
+void CActiveDeviceStateNotifier::Activate()
+/**
+ *
+ */
+    {
+    TRACE_FUNC
+    if (IsActive())
+        {
+        TRACE_INFO((_L("Still active")))
+        return;
+        }
+    iParent.Ldd().AlternateDeviceStatusNotify(iStatus, iDeviceState);
+    SetActive();
+    }
+