userlibandfileserver/fileserver/smassstorage/cbulkonlytransportusbcscldd.cpp
changeset 9 96e5fb8b040d
child 13 46fffbe7b5a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/smassstorage/cbulkonlytransportusbcscldd.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,935 @@
+/*
+* Copyright (c) 2004-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:
+*
+*/
+
+
+/**
+ @file
+ @internalTechnology
+*/
+
+#include "cbulkonlytransport.h"
+#include "cbulkonlytransportusbcscldd.h"
+#include "usbmsshared.h"
+#include "massstoragedebug.h"
+#include "cusbmassstorageserver.h"
+
+
+//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.
+
+LOCAL_D const TInt KUsbNumInterfacesOffset = 4;
+
+#ifdef MSDC_MULTITHREADED
+//Only used in DB. The first 2K of KMaxScBufferSize for sending CSW 
+static const TUint32 KCswBufferSize = 2 * 1024;
+#endif
+
+////////////////////////////////////
+/**
+Called by CBulkOnlyTransportUsbcScLdd to create an instance of CControlInterfaceUsbcScLdd
+
+@param aParent reference to the CBulkOnlyTransportUsbcScLdd
+*/
+
+
+CControlInterfaceUsbcScLdd* CControlInterfaceUsbcScLdd::NewL(CBulkOnlyTransportUsbcScLdd& aParent)
+	{
+	CControlInterfaceUsbcScLdd* self = new(ELeave) CControlInterfaceUsbcScLdd(aParent);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CActiveScheduler::Add(self);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+void CControlInterfaceUsbcScLdd::ConstructL()
+	{
+	}
+
+
+/**
+c'tor
+
+@param aParent reference to the CBulkOnlyTransportUsbcScLdd
+*/
+CControlInterfaceUsbcScLdd::CControlInterfaceUsbcScLdd(CBulkOnlyTransportUsbcScLdd& aParent)
+	:CActive(EPriorityStandard),
+	 iParent(aParent),
+	 iCurrentState(ENone)
+	{
+	}
+
+
+/**
+d'tor
+*/
+CControlInterfaceUsbcScLdd::~CControlInterfaceUsbcScLdd()
+	{
+	__FNLOG("CControlInterfaceUsbcScLdd::~CControlInterfaceUsbcScLdd ");
+	Cancel();
+	iEp0Buf.Close();
+	}
+
+TInt CControlInterfaceUsbcScLdd::OpenEp0()
+	{
+	TInt res = iParent.Ldd().OpenEndpoint(iEp0Buf,0);
+	return res;
+	}
+
+/**
+Called by CBulkOnlyTransport HwStart to start control interface
+*/
+TInt CControlInterfaceUsbcScLdd::Start()
+	{
+	__FNLOG("CControlInterfaceUsbcScLdd::Start ");
+	TInt res = ReadEp0Data();
+	return (res);
+	}
+
+
+/**
+Called by desctructor of CBulkOnlyTransportUsbcScLdd to stop control interface
+*/
+void CControlInterfaceUsbcScLdd::Stop()
+	{
+	__FNLOG("CControlInterfaceUsbcScLdd::Stop ");
+	if (!IsActive())
+		{
+		__PRINT(_L("Not active\n"));
+		return;
+		}
+
+	__PRINT(_L("\nStopping...\n"));
+
+
+	iCurrentState = ENone;
+
+	Cancel();
+	}
+
+
+/**
+Cancel outstanding request (if any)
+*/
+void CControlInterfaceUsbcScLdd::DoCancel()
+	{
+	__FNLOG("CControlInterfaceUsbcScLdd::DoCancel ");
+	switch(iCurrentState)
+		{
+		case EReadEp0Data:
+			iParent.Ldd().ReadCancel(KUsbcScEndpointZero);
+			break;
+		case ESendMaxLun:
+			iParent.Ldd().WriteCancel(KUsbcScEndpointZero);
+			break;
+		default:
+			__PRINT(_L("\nWrong state !\n"));
+			__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState));
+		}
+	}
+
+
+/**
+Implement CControlInterfaceUsbcScLdd state machine
+*/
+void CControlInterfaceUsbcScLdd::RunL()
+	{
+	__FNLOG("CControlInterfaceUsbcScLdd::RunL ");
+	if (iStatus != KErrNone)
+		{
+		__PRINT1(_L("Error %d in RunL\n"), iStatus.Int());
+
+		//read EP0  again
+		ReadEp0Data();
+		return;
+		}
+
+	ReadEp0Data();
+	}
+
+/**
+Actual Read to RDevUsbcScClient BIL
+*/
+TInt CControlInterfaceUsbcScLdd::ReadUsbEp0()
+	{
+	iCurrentState = EReadEp0Data;
+	iStatus = KRequestPending;
+	return iEp0Buf.GetBuffer (iEp0Packet,iEp0Size,iEp0Zlp,iStatus);
+	}
+
+
+/**
+Post a read request to EEndpoint0 to read request header
+*/
+TInt CControlInterfaceUsbcScLdd::ReadEp0Data()
+	{
+	__FNLOG("CControlInterfaceUsbcScLdd::ReadEp0Data ");
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		return KErrServerBusy;
+		}
+
+	TInt r = KErrNone;
+	do
+		{
+		r = ReadUsbEp0();
+		if (r == KErrCompletion)
+			{
+			iStatus = KErrNone;
+			DecodeEp0Data();
+			}
+		else if (r == KErrNone)
+			{
+			SetActive();
+			}
+		} while (((r == KErrCompletion) || (r == TEndpointBuffer::KStateChange)) && (!IsActive()));
+	return KErrNone;
+	}
+
+
+/**
+Decode request header and do appropriate action - get max LUN info or post a reset request
+*/
+void CControlInterfaceUsbcScLdd::DecodeEp0Data()
+	{
+	__FNLOG("CControlInterfaceUsbcScLdd::DecodeEp0Data ");
+
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceStillActive));
+		return;
+		}
+
+	TPtrC8 ep0ReadDataPtr((TUint8*)iEp0Packet, iEp0Size);
+	TInt err = iRequestHeader.Decode(ep0ReadDataPtr);
+
+	if(err != KErrNone)
+		return;
+
+    switch(iRequestHeader.iRequest)
+		{
+		//
+		// GET MAX LUN (0xFE)
+		//
+		case TUsbRequestHdr::EReqGetMaxLun:
+			{
+			__PRINT1(_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)
+                {
+    		    __PRINT(_L("GetMaxLun command packet check error"));
+                iParent.Ldd().EndpointZeroRequestError();
+                break;
+                }
+
+			TPtr8* ep0WriteDataPtr = NULL;
+			TUint ep0Length;
+			iEp0Buf.GetInBufferRange(((TAny*&)ep0WriteDataPtr),ep0Length);
+			ep0WriteDataPtr->SetLength(1);	//Return only 1 byte to host
+			ep0WriteDataPtr->Fill(0);
+			ep0WriteDataPtr->Fill(iParent.MaxLun());	// Supported Units
+			TInt length = ep0WriteDataPtr->Length();
+			err = iEp0Buf.WriteBuffer((TPtr8*)(ep0WriteDataPtr->Ptr()),length,ETrue,iStatus);
+
+			iCurrentState = ESendMaxLun;
+			SetActive();
+
+			return;
+			}
+		//
+		// RESET (0xFF)
+		//
+		case TUsbRequestHdr::EReqReset:
+			{
+			__PRINT(_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)
+                {
+			    __PRINT(_L("MSC Reset command packet check error"));
+                iParent.Ldd().EndpointZeroRequestError();
+                break;
+                }
+
+			iParent.HwStop();
+			iParent.Controller().Reset();
+			iParent.HwStart(ETrue);
+
+            err = iParent.Ldd().SendEp0StatusPacket();
+			return;
+			}
+		//
+		// Unknown?
+		//
+		default:
+			{
+			__PRINT(_L("DecodeEp0Data : Unknown Request"));
+
+			}
+		}
+		ReadEp0Data();  //try to get another request
+	}
+
+
+//
+// --- class CBulkOnlyTransportUsbcScLdd ---------------------------------------------------------
+//
+
+CBulkOnlyTransportUsbcScLdd::CBulkOnlyTransportUsbcScLdd(TInt aNumDrives,CUsbMassStorageController& aController)
+	:CBulkOnlyTransport(aNumDrives, aController)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::CBulkOnlyTransportUsbcScLdd");
+	}
+
+/**
+Constructs the CBulkOnlyTransportUsbcScLdd object
+*/
+void CBulkOnlyTransportUsbcScLdd::ConstructL()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::ConstructL()");
+	iControlInterface = CControlInterfaceUsbcScLdd::NewL(*this);
+	iDeviceStateNotifier = CActiveDeviceStateNotifierBase::NewL(*this, *this);
+	iChunk = new RChunk();
+	CActiveScheduler::Add(this);
+	}
+
+
+CBulkOnlyTransportUsbcScLdd::~CBulkOnlyTransportUsbcScLdd()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::~CBulkOnlyTransportUsbcScLdd");
+	if (iInterfaceConfigured)
+		{
+		TInt err = iSCReadEndpointBuf.Close(); 
+		err = iSCWriteEndpointBuf.Close();
+		delete iControlInterface ;
+		delete iDeviceStateNotifier;
+		delete iChunk;
+		}
+	}	
+
+RDevUsbcScClient& CBulkOnlyTransportUsbcScLdd::Ldd()
+	{
+	return iLdd;
+	}
+
+/**
+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 CBulkOnlyTransportUsbcScLdd::SetupConfigurationDescriptor(TBool aUnset)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::SetupConfigurationDescriptor");
+	TInt ret(KErrNone);
+
+	if ((ret = iLdd.Open(0)) != KErrNone)
+		return ret;
+
+	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);
+
+	if (aUnset)
+		{
+		iLdd.Close();
+		}
+
+	return ret;
+	}
+
+/**
+Set up interface descriptor
+
+@return KErrNone if operation was completed successfully, errorcode otherwise
+*/
+TInt CBulkOnlyTransportUsbcScLdd::SetupInterfaceDescriptors()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::SetupInterfaceDescriptors");
+	// 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
+	TUsbcScInterfaceInfoBuf 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].iBufferSize = KMaxScBufferSize;
+			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].iBufferSize = KMaxScBufferSize;
+			ifc().iEndpointData[1].iReadSize = KMaxScReadSize;
+
+			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
+
+	if (d_caps().iHighSpeed)
+		{
+		// Tell the Protocol about it, because it might want to do some
+		// optimizing too.
+		iProtocol->ReportHighSpeedDevice();
+		}
+
+	if ((ret = iLdd.SetInterface(0, ifc)) == KErrNone)
+		{
+		return (iLdd.FinalizeInterface(iChunk));
+		}
+	return ret;
+	}
+
+void CBulkOnlyTransportUsbcScLdd::ReleaseInterface()
+	{
+	iLdd.ReleaseInterface(0);
+	}
+
+
+TInt CBulkOnlyTransportUsbcScLdd::StartControlInterface()
+	{
+	return iControlInterface->Start();
+	}
+
+void CBulkOnlyTransportUsbcScLdd::CancelControlInterface()
+	{
+	iControlInterface->Cancel();
+	}
+
+void CBulkOnlyTransportUsbcScLdd::ActivateDeviceStateNotifier()
+	{
+	iDeviceStateNotifier->Activate();
+	}
+
+void CBulkOnlyTransportUsbcScLdd::CancelDeviceStateNotifier()
+	{
+	iDeviceStateNotifier->Cancel();
+	}
+
+
+void CBulkOnlyTransportUsbcScLdd::CancelReadWriteRequests()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::CancelReadWriteRequests");
+	TUsbcScChunkHeader chunkHeader(*iChunk);
+	for (TInt i = 0; i < chunkHeader.iAltSettings->iNumOfAltSettings; i++)
+		{
+		TInt8* endpoint = (TInt8*) (chunkHeader.iAltSettings->iAltTableOffset[i] + (TInt) iChunk->Base());
+		TInt numOfEps = chunkHeader.GetNumberOfEndpoints(i);
+        __ASSERT_DEBUG(numOfEps >= 0, User::Invariant());
+		for (TInt j = 1; j <= numOfEps; j++)
+			{
+			TUsbcScHdrEndpointRecord* endpointInf = (TUsbcScHdrEndpointRecord*) &(endpoint[j * chunkHeader.iAltSettings->iEpRecordSize]);
+			if (endpointInf->Direction() == KUsbScHdrEpDirectionOut)
+				{
+				iLdd.ReadCancel(endpointInf->iBufferNo);
+				}
+			if (endpointInf->Direction() == KUsbScHdrEpDirectionIn)
+				{
+				iLdd.WriteCancel(endpointInf->iBufferNo);
+				}
+			}
+		}
+	}
+
+void CBulkOnlyTransportUsbcScLdd::AllocateEndpointResources()
+	{
+	TUsbcScChunkHeader chunkHeader(*iChunk);
+	for (TInt i = 0; i < chunkHeader.iAltSettings->iNumOfAltSettings; i++)
+		{
+		TInt8* endpoint = (TInt8*) (chunkHeader.iAltSettings->iAltTableOffset[i] + (TInt) iChunk->Base()); 
+
+		for (TInt j = 1; j <= chunkHeader.GetNumberOfEndpoints(i); j++) 
+			{
+			TUsbcScHdrEndpointRecord* endpointInf = (TUsbcScHdrEndpointRecord*) &(endpoint[j * chunkHeader.iAltSettings->iEpRecordSize]);
+			if (endpointInf->Direction() == KUsbScHdrEpDirectionOut)
+				{
+				iOutEndpoint = j;
+				}
+			if (endpointInf->Direction() == KUsbScHdrEpDirectionIn)
+				{
+				iInEndpoint = j;
+				}
+			}
+		}
+		
+	__PRINT(_L("CBulkOnlyTransportUsbcScLdd::Start  - Setting up DMA and double buffering\n"));
+	// Set up DMA if possible (errors are non-critical)
+	TInt err = iLdd.AllocateEndpointResource(iOutEndpoint, EUsbcEndpointResourceDMA);
+	if (err != KErrNone)
+		{
+		__PRINT1(_L("Set DMA on OUT endpoint failed with error code: %d"), err);
+		}
+	err = iLdd.AllocateEndpointResource(iInEndpoint, EUsbcEndpointResourceDMA);
+	if (err != KErrNone)
+		{
+		__PRINT1(_L("Set DMA on IN endpoint failed with error code: %d"), err);
+		}
+
+	// Set up Double Buffering if possible (errors are non-critical)
+	err = iLdd.AllocateEndpointResource(iOutEndpoint, EUsbcEndpointResourceDoubleBuffering);
+	if (err != KErrNone)
+		{
+		__PRINT1(_L("Set Double Buffering on OUT endpoint failed with error code: %d"), err);
+		}
+	err = iLdd.AllocateEndpointResource(iInEndpoint, EUsbcEndpointResourceDoubleBuffering);
+	if (err != KErrNone)
+		{
+		__PRINT1(_L("Set Double Buffering on IN endpoint failed with error code: %d"), err);
+		}
+
+	
+	err = OpenEndpoints();
+	}
+
+TInt CBulkOnlyTransportUsbcScLdd::OpenEndpoints()
+	{
+	TInt res = iLdd.OpenEndpoint(iSCReadEndpointBuf, iOutEndpoint);
+	if (res == KErrNone)
+		{
+		res = iLdd.OpenEndpoint(iSCWriteEndpointBuf, iInEndpoint);
+		if (res == KErrNone)
+			{
+			iSCWriteEndpointBuf.GetInBufferRange((TAny*&)iDataPtr, iInBufferLength);
+			res = iControlInterface->OpenEp0();
+			}
+		return res;
+		}
+
+	return res;
+	}
+
+
+TInt CBulkOnlyTransportUsbcScLdd::GetDeviceStatus(TUsbcDeviceState& deviceStatus)
+	{
+	return iLdd.DeviceStatus(deviceStatus);
+	}
+
+void CBulkOnlyTransportUsbcScLdd::FlushData()
+	{
+	// Intentionally Left Blank Do Nothing 
+	}
+
+/**
+ * Read out rest data from OutEndpoint and discard them
+ */
+void CBulkOnlyTransportUsbcScLdd::ReadAndDiscardData(TInt /*aBytes*/)
+	{
+	__FNLOG("CBulkOnlyTransport::ReadAndDiscardData");
+	TRequestStatus status;
+	TInt r = KErrNone; // Lets assume there is no data
+	do
+		{
+		iSCReadSize = 0;
+		status = KErrNone;
+		r = iSCReadEndpointBuf.TakeBuffer(iSCReadData,iSCReadSize,iReadZlp,status);
+		iSCReadEndpointBuf.Expire();
+		}
+	while (r == KErrCompletion);
+
+	if (r == KErrNone)
+		{
+		TRequestStatus* stat = &status;
+		User::RequestComplete(stat, KErrNone);
+		}
+	}
+
+/**
+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 CBulkOnlyTransportUsbcScLdd::BytesAvailable()
+	{
+	// Intentionally Left Blank Do Nothing 
+	return 0;
+	}
+
+void CBulkOnlyTransportUsbcScLdd::StallEndpointAndWaitForClear()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::StallEndpointAndWaitForClear");
+
+	// Now stall this endpoint
+	__PRINT1(_L("Stalling endpoint %d"), iInEndpoint);
+	TInt r = iLdd.HaltEndpoint(iInEndpoint);
+	if (r != KErrNone)
+		{
+		__PRINT2(_L("Error: stalling ep %d failed: %d"), iInEndpoint, r);
+		}
+	TEndpointState ep_state;
+	TInt i = 0;
+	do
+		{
+		// Wait for 10ms before checking the ep status
+		User::After(10000);
+		iLdd.EndpointStatus(iInEndpoint, ep_state);
+		if (++i >= 550)
+			{
+			// 5.5 secs should be enough (see 9.2.6.1 Request Processing Timing)
+			__PRINT1(_L("Error: Checked for ep %d de-stall for 5.5s - giving up now"), iInEndpoint);
+			// We can now only hope for a Reset Recovery
+			return;
+			}
+		} while ((ep_state == EEndpointStateStalled) && iStarted);
+	__PRINT2(_L("Checked for ep %d de-stall: %d time(s)"), iInEndpoint, i);
+	}
+
+/**
+Read CBW data from the host and decode it.
+*/
+void CBulkOnlyTransportUsbcScLdd::ReadCBW()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::ReadCBW");
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive)); 
+		return;
+		}
+	TInt r = KErrNone;
+	do
+		{
+		r = ReadUsb();
+		if ((r == KErrCompletion) && (iSCReadSize == KCbwLength))  
+			{
+			iCurrentState = EWaitForCBW;
+			iStatus = KErrNone;
+			DecodeCBW();
+			iSCReadSize = 0;
+			}
+		else if (r == KErrNone)
+			{
+			iCurrentState = EWaitForCBW;
+			SetActive();
+			}
+		else if ((r == KErrCompletion) && (iSCReadSize != KCbwLength))
+			{
+			ExpireData(iSCReadData);
+			}
+		}while ((r == KErrCompletion) && (!IsActive()));
+	}
+
+void CBulkOnlyTransportUsbcScLdd::ExpireData(TAny* aAddress)
+	{
+	if (aAddress)
+		{
+		iSCReadEndpointBuf.Expire(aAddress);
+		}
+	else
+		{
+		iSCReadEndpointBuf.Expire();
+		}
+	}
+
+void CBulkOnlyTransportUsbcScLdd::ProcessCbwEvent()
+	{
+	ReadCBW();
+	}
+
+/**
+Request data form the host for the protocol
+
+@param aLength amount of data (in bytes) to be received from the host
+*/
+void CBulkOnlyTransportUsbcScLdd::ReadData(TUint /*aLength*/)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::ReadData");
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+		return;
+		}
+	TInt r = KErrNone;
+	do
+		{
+		r = ReadUsb();
+		iCurrentState = EReadingData;
+		if (r == KErrCompletion)
+			{
+			iReadBufPtr.Set((TUint8*) iSCReadData, iSCReadSize, iSCReadSize);
+			iStatus = KErrNone;
+			ProcessDataFromHost();
+			iSCReadSize = 0;
+			}
+		else if (r == KErrNone)
+			{
+			iSCReadSize = 0;
+			SetActive();
+			}
+
+		}while ((r == KErrCompletion) && (!IsActive()));
+	}
+
+void CBulkOnlyTransportUsbcScLdd::ProcessDataFromHost()
+	{
+	TInt ret = KErrNone;
+		{
+		if (iReadSetUp)
+			{
+			ret = iProtocol->ReadComplete(KErrNone);
+			}
+#ifndef MSDC_MULTITHREADED
+		ExpireData(iSCReadData);
+#endif
+		TUint deviceDataLength = iSCReadSize; // What was written to the disk // 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 is initially set to host data length as we do not know how much data is there in the 'LDD transfer'. 
+			//After a TakeBuffer call, iSCReadSize in updated and set to deviceDataLength
+			iDataResidue -= deviceDataLength;
+			}
+		else
+			{
+			iDataResidue -= deviceDataLength;
+
+			// 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)
+				{
+				__PRINT(_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);
+			}
+		}
+	}
+
+void CBulkOnlyTransportUsbcScLdd::WriteUsb(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired)
+	{
+	TUint aOffset = (TUint) aDes.Ptr() - (TUint) iChunk->Base();
+	iSCWriteEndpointBuf.WriteBuffer(aOffset, aLength, aZlpRequired, aStatus);
+	}
+
+void CBulkOnlyTransportUsbcScLdd::SetCbwPtr()
+	{
+	iCbwBufPtr.Set((TUint8*)iSCReadData, iSCReadSize);
+	}
+
+TPtr8& CBulkOnlyTransportUsbcScLdd::SetCommandBufPtr(TUint aLength)
+	{
+	TPtr8 writeBuf((TUint8*) iDataPtr, aLength);
+	iCommandBufPtr.Set(writeBuf);
+	return iCommandBufPtr;
+	}
+
+void CBulkOnlyTransportUsbcScLdd::SetReadDataBufPtr(TUint /*aLength*/)
+	{
+	// Do nothing for now 
+	}
+
+TPtr8& CBulkOnlyTransportUsbcScLdd::SetDataBufPtr()
+	{
+	TPtr8 writeBuf((TUint8*) iDataPtr, iInBufferLength);
+	iDataBufPtr.Set(writeBuf);
+	return iDataBufPtr;
+	}
+
+void CBulkOnlyTransportUsbcScLdd::SetPaddingBufPtr(TUint aLength)
+	{
+	TPtr8 writeBuf((TUint8*) iDataPtr, aLength, aLength);
+	iPaddingBufPtr.Set(writeBuf);
+	}
+
+void CBulkOnlyTransportUsbcScLdd::SetCswBufPtr(TUint aLength)
+	{
+	TPtr8 writeBuf((TUint8*) iDataPtr, aLength, aLength);
+	iCswBufPtr.Set(writeBuf);
+	}
+
+void CBulkOnlyTransportUsbcScLdd::ProcessReadingDataEvent()
+	{
+	ReadData();
+	}
+
+TInt CBulkOnlyTransportUsbcScLdd::ReadUsb(TUint /*aLength*/)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::ReadUSB");
+	return iSCReadEndpointBuf.TakeBuffer(iSCReadData,iSCReadSize,iReadZlp,iStatus);
+	}
+
+void CBulkOnlyTransportUsbcScLdd::DiscardData(TUint aLength)
+	{
+	TUint c = 0;
+	TRequestStatus status;
+	TInt r = KErrNone;
+	while (c < aLength)
+		{
+		iSCReadSize = 0;
+		status = KErrNone;
+		r = iSCReadEndpointBuf.TakeBuffer(iSCReadData,iSCReadSize,iReadZlp,status);
+		c += iSCReadSize;
+		if (r == KErrNone)
+			User::WaitForRequest(status);
+		if (r == KErrCompletion)
+			{
+			iSCReadEndpointBuf.Expire();
+			}
+		iSCReadSize = 0;
+		}
+	}
+
+void CBulkOnlyTransportUsbcScLdd::WriteToClient(TUint aLength)
+	{
+	TUint c = 0;
+	TRequestStatus status;
+	TInt r = KErrNone;
+	while (c < aLength)
+		{
+		iSCReadSize = 0;
+		status = KErrNone;
+		r = iSCReadEndpointBuf.TakeBuffer(iSCReadData,iSCReadSize,iReadZlp,status);
+		c += iSCReadSize;
+		iProtocol->ReadComplete(KErrGeneral);
+		if (r == KErrNone)
+			User::WaitForRequest(status);
+		if (r == KErrCompletion)
+			{
+			iSCReadEndpointBuf.Expire();
+			}
+		iSCReadSize = 0;
+		}
+	}
+
+#ifdef MSDC_MULTITHREADED
+void CBulkOnlyTransportUsbcScLdd::GetBufferPointers(TPtr8& aDes1, TPtr8& aDes2)
+	{
+	//for DB
+	TUint length = (TUint) (iInBufferLength - KCswBufferSize) / 2;
+
+	TUint8* start = (TUint8*) (iDataPtr) + KCswBufferSize ; // 'first' buffer
+	aDes1.Set(start, length, length);
+
+	start = (TUint8*) (iDataPtr) + KCswBufferSize + length; // 'second' buffer
+	aDes2.Set(start, length, length);
+	}
+#endif
+
+void CBulkOnlyTransportUsbcScLdd::Activate(TRequestStatus& aStatus, TUint& aDeviceState)
+    {
+	iLdd.AlternateDeviceStatusNotify(aStatus, aDeviceState);
+    }
+
+
+void CBulkOnlyTransportUsbcScLdd::Cancel()
+    {
+	iLdd.AlternateDeviceStatusNotifyCancel();
+    }
+
+
+
+