userlibandfileserver/fileserver/smassstorage/cbulkonlytransportusbcldd.cpp
changeset 9 96e5fb8b040d
child 13 46fffbe7b5a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/smassstorage/cbulkonlytransportusbcldd.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,830 @@
+/*
+* 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 "cbulkonlytransportusbcldd.h"
+#include "usbmsshared.h"
+#include "massstoragedebug.h"
+#include "cusbmassstorageserver.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.
+
+LOCAL_D const TInt KUsbNumInterfacesOffset = 4;
+
+////////////////////////////////////
+/**
+Called by CBulkOnlyTransportUsbcLdd to create an instance of CControlInterfaceUsbcLdd
+
+@param aParent reference to the CBulkOnlyTransportUsbcLdd
+*/
+
+
+CControlInterfaceUsbcLdd* CControlInterfaceUsbcLdd::NewL(CBulkOnlyTransportUsbcLdd& aParent)
+	{
+	CControlInterfaceUsbcLdd* self = new(ELeave) CControlInterfaceUsbcLdd(aParent);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CActiveScheduler::Add(self);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+void CControlInterfaceUsbcLdd::ConstructL()
+	{
+	}
+
+
+/**
+c'tor
+
+@param aParent reference to the CBulkOnlyTransportUsbcLdd
+*/
+CControlInterfaceUsbcLdd::CControlInterfaceUsbcLdd(CBulkOnlyTransportUsbcLdd& aParent)
+	:CActive(EPriorityStandard),
+	 iParent(aParent),
+	 iCurrentState(ENone)
+	{
+	}
+
+
+/**
+d'tor
+*/
+CControlInterfaceUsbcLdd::~CControlInterfaceUsbcLdd()
+	{
+	__FNLOG("CControlInterfaceUsbcLdd::~CControlInterfaceUsbcLdd ");
+	Cancel();
+	}
+
+
+/**
+Called by CBulkOnlyTransport HwStart to start control interface
+*/
+TInt CControlInterfaceUsbcLdd::Start()
+	{
+	__FNLOG("CControlInterfaceUsbcLdd::Start ");
+	TInt res = ReadEp0Data();
+	return (res);
+	}
+
+
+/**
+Called by desctructor of CBulkOnlyTransportUsbcLdd to stop control interface
+*/
+void CControlInterfaceUsbcLdd::Stop()
+	{
+	__FNLOG("CControlInterfaceUsbcLdd::Stop ");
+	if (!IsActive())
+		{
+		__PRINT(_L("Not active\n"));
+		return;
+		}
+
+	__PRINT(_L("\nStopping...\n"));
+
+
+	iCurrentState = ENone;
+
+	Cancel();
+	}
+
+
+/**
+Cancel outstanding request (if any)
+*/
+void CControlInterfaceUsbcLdd::DoCancel()
+	{
+	__FNLOG("CControlInterfaceUsbcLdd::DoCancel ");
+	switch(iCurrentState)
+		{
+		case EReadEp0Data:
+			iParent.Ldd().ReadCancel(EEndpoint0);
+			break;
+		case ESendMaxLun:
+			iParent.Ldd().WriteCancel(EEndpoint0);
+			break;
+		default:
+			__PRINT(_L("\nWrong state !\n"));
+			__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState));
+		}
+	}
+
+
+/**
+Implement CControlInterfaceUsbcLdd state machine
+*/
+void CControlInterfaceUsbcLdd::RunL()
+	{
+	__FNLOG("CControlInterfaceUsbcLdd::RunL ");
+	if (iStatus != KErrNone)
+		{
+		__PRINT1(_L("Error %d in RunL\n"), iStatus.Int());
+
+		//read EP0  again
+		ReadEp0Data();
+		return;
+		}
+
+	switch (iCurrentState)
+		{
+		case ESendMaxLun:
+			ReadEp0Data();
+			break;
+
+		case EReadEp0Data:
+			DecodeEp0Data();
+			break;
+
+		default:
+			__PRINT(_L("  error: (Shouldn't end up here...)\n"));
+			__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState));
+			break;
+		}
+	return;
+	}
+
+
+/**
+Post a read request to EEndpoint0 to read request header
+*/
+TInt CControlInterfaceUsbcLdd::ReadEp0Data()
+	{
+	__FNLOG("CControlInterfaceUsbcLdd::ReadEp0Data ");
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		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 CControlInterfaceUsbcLdd::DecodeEp0Data()
+	{
+	__FNLOG("CControlInterfaceUsbcLdd::DecodeEp0Data ");
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceStillActive));
+		return;
+		}
+
+	TInt err = iRequestHeader.Decode(iData);
+
+	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;
+                }
+			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:
+			{
+			__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 CBulkOnlyTransportUsbcLdd ---------------------------------------------------------
+//
+
+CBulkOnlyTransportUsbcLdd::CBulkOnlyTransportUsbcLdd(TInt aNumDrives,CUsbMassStorageController& aController)
+	:CBulkOnlyTransport(aNumDrives, aController),
+	 iSwap(ETrue)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::CBulkOnlyTransportUsbcLdd");
+	}
+
+/**
+Constructs the CBulkOnlyTransportUsbcLdd object
+*/
+void CBulkOnlyTransportUsbcLdd::ConstructL()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::ConstructL()");
+	iControlInterface = CControlInterfaceUsbcLdd::NewL(*this);
+	iDeviceStateNotifier = CActiveDeviceStateNotifierBase::NewL(*this, *this);
+	CActiveScheduler::Add(this);
+	}
+
+CBulkOnlyTransportUsbcLdd::~CBulkOnlyTransportUsbcLdd()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::~CBulkOnlyTransportUsbcLdd");
+	if (iInterfaceConfigured)
+		{
+		delete iControlInterface ;
+		delete iDeviceStateNotifier;
+		}
+	}	
+
+RDevUsbcClient& CBulkOnlyTransportUsbcLdd::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 CBulkOnlyTransportUsbcLdd::SetupConfigurationDescriptor(TBool aUnset)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::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 CBulkOnlyTransportUsbcLdd::SetupInterfaceDescriptors()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::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
+	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;
+			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;
+			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;
+	}
+
+void CBulkOnlyTransportUsbcLdd::ReleaseInterface()
+	{
+	iLdd.ReleaseInterface(0);
+	}
+
+TInt CBulkOnlyTransportUsbcLdd::StartControlInterface()
+	{
+	return iControlInterface->Start();
+	}
+
+void CBulkOnlyTransportUsbcLdd::CancelControlInterface()
+	{
+	iControlInterface->Cancel();
+	}
+
+void CBulkOnlyTransportUsbcLdd::ActivateDeviceStateNotifier()
+	{
+	iDeviceStateNotifier->Activate();
+	}
+
+void CBulkOnlyTransportUsbcLdd::CancelDeviceStateNotifier()
+	{
+	iDeviceStateNotifier->Cancel();
+	}
+
+void CBulkOnlyTransportUsbcLdd::CancelReadWriteRequests()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::CancelReadWriteRequests");
+	iLdd.WriteCancel(InEndpoint);
+	iLdd.ReadCancel(OutEndpoint);
+	}
+
+void CBulkOnlyTransportUsbcLdd::AllocateEndpointResources()
+	{
+		// Set up DMA if possible (errors are non-critical)
+	TInt err = iLdd.AllocateEndpointResource(OutEndpoint, EUsbcEndpointResourceDMA);
+	if (err != KErrNone)
+		{
+		__PRINT1(_L("Set DMA on OUT endpoint failed with error code: %d"), err);
+		}
+	err = iLdd.AllocateEndpointResource(InEndpoint, 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(OutEndpoint, EUsbcEndpointResourceDoubleBuffering);
+	if (err != KErrNone)
+		{
+		__PRINT1(_L("Set Double Buffering on OUT endpoint failed with error code: %d"), err);
+		}
+	err = iLdd.AllocateEndpointResource(InEndpoint, EUsbcEndpointResourceDoubleBuffering);
+	if (err != KErrNone)
+		{
+		__PRINT1(_L("Set Double Buffering on IN endpoint failed with error code: %d"), err);
+		}
+	}
+
+TInt CBulkOnlyTransportUsbcLdd::GetDeviceStatus(TUsbcDeviceState& deviceStatus)
+	{
+	return iLdd.DeviceStatus(deviceStatus);
+	}
+
+void CBulkOnlyTransportUsbcLdd::FlushData()
+	{
+	TInt bytes;
+	const TInt err = iLdd.QueryReceiveBuffer(OutEndpoint, bytes);
+	if (err != KErrNone || bytes <= 0)
+		{
+		__PRINT1(_L("Error: err=%d bytes=%d"), bytes);
+		}
+	else
+		{
+		__PRINT1(_L("RxBuffer has %d bytes"), bytes);
+		ReadAndDiscardData(bytes);
+		}
+	}
+/**
+ * Read out rest data from OutEndpoint and discard them
+ */
+void CBulkOnlyTransportUsbcLdd::ReadAndDiscardData(TInt aBytes)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::ReadAndDiscardData");
+	iDiscardBuf.SetMax();
+	const TUint bufsize = static_cast<TUint>(iDiscardBuf.Length());
+	TRequestStatus status;
+	while (aBytes > 0)
+		{
+		__PRINT1(_L("Bytes still to be read: %d\n"), aBytes);
+		iLdd.ReadOneOrMore(status, OutEndpoint, iDiscardBuf, bufsize);
+		User::WaitForRequest(status);
+		TInt err = status.Int();
+		if (err != KErrNone)
+			{
+			// Bad.
+			break;
+			}
+		aBytes -= iDiscardBuf.Length();
+		}
+	}
+
+/**
+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 CBulkOnlyTransportUsbcLdd::BytesAvailable()
+	{
+	TInt bytes = 0;
+	TInt err = iLdd.QueryReceiveBuffer(OutEndpoint, bytes);
+	if (err != KErrNone)
+		bytes = 0;
+	return bytes;
+	}
+
+
+void CBulkOnlyTransportUsbcLdd::StallEndpointAndWaitForClear()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::StallEndpointAndWaitForClear");
+
+	// Now stall this endpoint
+	__PRINT1(_L("Stalling endpoint %d"), InEndpoint);
+	TInt r = iLdd.HaltEndpoint(InEndpoint);
+	if (r != KErrNone)
+		{
+		__PRINT2(_L("Error: stalling ep %d failed: %d"), InEndpoint, r);
+		}
+	TEndpointState ep_state;
+	TInt i = 0;
+	do
+		{
+		// Wait for 10ms before checking the ep status
+		User::After(10000);
+		iLdd.EndpointStatus(InEndpoint, 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"), InEndpoint);
+			// 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)"), InEndpoint, i);
+	}
+
+
+/**
+Read CBW data (KCbwLength) from the host into the read buffer.
+*/
+void CBulkOnlyTransportUsbcLdd::ReadCBW()
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::ReadCBW");
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+		return;
+		}
+
+	iCbwBuf.SetMax();
+	iLdd.ReadUntilShort(iStatus, OutEndpoint, iCbwBuf, KCbwLength);
+
+	iCurrentState = EWaitForCBW;
+	SetActive();
+	}
+
+void CBulkOnlyTransportUsbcLdd::ExpireData(TAny* /*aAddress*/)
+	{
+	// Intentionally left blank
+	}
+
+void CBulkOnlyTransportUsbcLdd::ProcessCbwEvent()
+	{
+	DecodeCBW();
+	}
+
+
+/**
+Request data form the host for the protocol
+
+@param aLength amount of data (in bytes) to be received from the host
+*/
+void CBulkOnlyTransportUsbcLdd::ReadData(TUint aLength)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcLdd::ReadData");
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+		return;
+		}
+	
+	SetReadDataBufPtr(aLength);
+	iLdd.Read(iStatus, OutEndpoint, iReadBufPtr, aLength);
+
+	iCurrentState = EReadingData;
+	SetActive();
+	}
+
+void CBulkOnlyTransportUsbcLdd::WriteUsb(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired)
+	{
+	iLdd.Write(aStatus, InEndpoint, aDes, aLength, aZlpRequired);
+	}
+
+void CBulkOnlyTransportUsbcLdd::SetCbwPtr()
+	{
+	iCbwBufPtr.Set(iCbwBuf.Ptr(), iCbwBuf.Length());
+	}
+
+TPtr8& CBulkOnlyTransportUsbcLdd::SetCommandBufPtr(TUint aLength)
+	{
+	iCommandBufPtr.Set((TUint8*) iCommandBuf.Ptr(), aLength, aLength );
+	return iCommandBufPtr;
+	}
+
+void CBulkOnlyTransportUsbcLdd::SetReadDataBufPtr(TUint aLength) //Write10(Host->Device
+	{
+	if (iSwap)
+		{
+		iDataBuf1.SetLength(aLength);
+		iReadBufPtr.Set(iDataBuf1.LeftTPtr(iDataBuf1.Length()));
+		iSwap = EFalse;
+		}
+	else
+		{
+		iDataBuf2.SetLength(aLength);
+		iReadBufPtr.Set(iDataBuf2.LeftTPtr(iDataBuf2.Length()));
+		iSwap = ETrue;
+		}
+	}
+
+TPtr8& CBulkOnlyTransportUsbcLdd::SetDataBufPtr() //Read10(Device->Host)
+	{
+	if (iSwap)
+		{
+		iDataBufPtr.Set((TUint8*) iDataBuf1.Ptr(), KMaxBufSize, KMaxBufSize);
+		iSwap = EFalse;
+		}
+	else
+		{
+		iDataBufPtr.Set((TUint8*) iDataBuf2.Ptr(), KMaxBufSize, KMaxBufSize);
+		iSwap = ETrue;
+		}
+	return iDataBufPtr;
+	}
+
+void CBulkOnlyTransportUsbcLdd::SetPaddingBufPtr(TUint aLength)
+	{
+	iPaddingBufPtr.Set((TUint8*) iBuf.Ptr(), aLength, aLength );
+	}
+
+
+void CBulkOnlyTransportUsbcLdd::SetCswBufPtr(TUint aLength)
+	{
+	iCswBufPtr.Set((TUint8*) iCswBuf.Ptr(), aLength, aLength );
+	}
+
+void CBulkOnlyTransportUsbcLdd::ProcessReadingDataEvent()
+	{
+	TInt ret = KErrNone;
+    FOREVER
+		{
+		if (iReadSetUp)
+			{
+			ret = iProtocol->ReadComplete(KErrNone);
+			}
+
+		TUint deviceDataLength = iBufSize; // This is the amount (maximum in case of SC Ldd) to be read next.
+
+		if(ret == KErrCompletion)
+			{
+			// The protocol has indicated with KErrCompletion that sufficient
+			// data is available in the buffer to process the transfer immediately.
+
+			iDataResidue -= iReadBufPtr.Length();
+			SetReadDataBufPtr(deviceDataLength);
+
+			iLdd.Read(iStatus, OutEndpoint, iReadBufPtr, deviceDataLength);
+			User::WaitForRequest(iStatus);
+			if (iStatus != KErrNone)
+				{
+				// An error occurred - halt endpoints for reset recovery
+				__PRINT1(_L("Error %d in EReadingData, halt endpoints \n"), 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
+
+            iDataResidue -= iReadBufPtr.Length();
+			ReadData(deviceDataLength);
+			break;
+			}
+		else
+			{
+			// The protocol has indicated that transfer is
+			// complete, so send the CSW response to the host.
+			iDataResidue -= iReadBufPtr.Length();
+			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);
+			break;
+			}
+		}
+
+	}
+
+void CBulkOnlyTransportUsbcLdd::DiscardData(TUint aLength)
+	{
+	iBuf.SetLength(KBOTMaxBufSize);
+	TUint c = 0;
+	TRequestStatus status;
+	while (c < aLength)
+		{
+		TInt len;
+		if (aLength - c >  KBOTMaxBufSize)
+			{
+			len = KBOTMaxBufSize;
+			}
+		else
+			{
+			len = aLength - c;
+			}
+
+		iLdd.Read(status, OutEndpoint, iBuf, len);
+		User::WaitForRequest(status);
+		c +=  KBOTMaxBufSize;
+		}
+	}
+
+void CBulkOnlyTransportUsbcLdd::WriteToClient(TUint aLength)
+	{
+	SetDataBufPtr();
+	iLdd.Read(iStatus, OutEndpoint, iDataBufPtr, aLength);
+    User::WaitForRequest(iStatus);
+    iProtocol->ReadComplete(KErrGeneral);
+	}
+
+#ifdef MSDC_MULTITHREADED
+void CBulkOnlyTransportUsbcLdd::GetBufferPointers(TPtr8& aDes1, TPtr8& aDes2)
+	{
+	aDes1.Set((TUint8*) iDataBuf1.Ptr(), KMaxBufSize, KMaxBufSize);
+	aDes2.Set((TUint8*) iDataBuf2.Ptr(), KMaxBufSize, KMaxBufSize);
+	}
+#endif
+
+void CBulkOnlyTransportUsbcLdd::Activate(TRequestStatus& aStatus, TUint& aDeviceState)
+    {
+	iLdd.AlternateDeviceStatusNotify(aStatus, aDeviceState);
+    }
+
+
+void CBulkOnlyTransportUsbcLdd::Cancel()
+    {
+	iLdd.AlternateDeviceStatusNotifyCancel();
+    }
+
+
+
+