userlibandfileserver/fileserver/smassstorage/cbulkonlytransport.cpp
changeset 43 96e5fb8b040d
child 269 d57b86b1867a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/smassstorage/cbulkonlytransport.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,918 @@
+// 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 "cbulkonlytransportusbcscldd.h"
+#include "usbmsshared.h"
+#include "massstoragedebug.h"
+#include "cusbmassstorageserver.h"
+
+
+//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;
+
+
+
+/**
+ 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))
+		{
+        __PRINT1(_L("TUsbRequestHdr::Decode buffer invalid length %d"), aBuffer.Length());
+		return KErrGeneral;
+		}
+
+	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));
+    __PRINT5(_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) ? (TBool)ETrue : (TBool)EFalse;
+	}
+
+//-------------------------------------
+/**
+Create an object of a class derived from CBulkOnlyTransport (default to CBulkOnlyTransportUsbcLdd object)
+@param aNumDrives - The number of drives available for MS
+@param aController - reference to the parent
+@return pointer to newly created derived class object
+*/
+CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CUsbMassStorageController& aController)
+	{
+	__FNLOG("CBulkOnlyTransport::NewL()");
+	
+	return NewL(aNumDrives,aController, (CUsbMassStorageController::TTransportldd) 1);
+	}
+
+/**
+Create an object of a class derived from CBulkOnlyTransport 
+@param aNumDrives - The number of drives available for MS
+@param aController - reference to the parent
+@param aTransportLddFlag - Type of usb client ldd
+@return pointer to newly created derived class object
+*/
+CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CUsbMassStorageController& aController, CUsbMassStorageController::TTransportldd aTransportLddFlag)
+	{
+	__FNLOG("CBulkOnlyTransport::NewL()");
+
+	if (aNumDrives <=0 || static_cast<TUint>(aNumDrives) > KUsbMsMaxDrives)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	CBulkOnlyTransportUsbcScLdd* scTransport;
+	CBulkOnlyTransportUsbcLdd* nonscTransport;
+	switch (aTransportLddFlag)
+		{
+		case 1: 
+				nonscTransport = new(ELeave) CBulkOnlyTransportUsbcLdd(aNumDrives, aController);
+				return nonscTransport;
+
+		case 2: 
+				scTransport = new(ELeave) CBulkOnlyTransportUsbcScLdd(aNumDrives, aController);
+				return scTransport;
+		default:
+				return NULL;
+
+		}
+	}
+
+
+TInt CBulkOnlyTransport::InitialiseTransportL(TInt aTransportLddFlag)
+	{
+	__FNLOG("CBulkOnlyTransportUsbcScLdd::InitialiseTransportL()");
+	TInt ret = KErrNone;
+	MTransportBase* transport;
+	iController.GetTransport(transport);
+	switch (aTransportLddFlag)
+		{
+		case 2: 
+				ret = ((CBulkOnlyTransportUsbcScLdd*) transport)->Ldd().Open(0);
+				if (ret != KErrNone)
+					{
+					return ret;
+					}
+				else
+					{
+					((CBulkOnlyTransportUsbcScLdd*) transport)->Ldd().Close();		
+					CleanupStack::PushL(transport);
+					((CBulkOnlyTransportUsbcScLdd*) transport)->ConstructL();
+					CleanupStack::Pop(transport);
+					return ret;
+					}
+		case 1:
+				ret = ((CBulkOnlyTransportUsbcLdd*) transport)->Ldd().Open(0);
+				if (ret != KErrNone)
+					{
+					return ret;
+					}
+				else
+					{
+					((CBulkOnlyTransportUsbcLdd*) transport)->Ldd().Close();
+					CleanupStack::PushL(transport);
+					((CBulkOnlyTransportUsbcLdd*) transport)->ConstructL();
+					CleanupStack::Pop(transport);
+					return ret;
+					}
+		default:
+				return KErrNotFound;
+		}
+	}	
+
+/**
+c'tor
+@param aNumDrives - The number of drives available for MS
+@param aController - reference to the parent
+*/
+CBulkOnlyTransport::CBulkOnlyTransport(TInt aNumDrives,CUsbMassStorageController& aController):
+	CActive(EPriorityStandard),
+	iMaxLun(aNumDrives-1),
+	iController(aController),
+	iStallAllowed(ETrue),
+	iInterfaceConfigured(EFalse),
+	iCommandBufPtr(NULL,0),
+	iDataBufPtr(NULL,0),
+	iCswBufPtr(NULL,0),
+	iPaddingBufPtr(NULL,0),
+	iWriteBufPtr(NULL,0),
+	iReadBufPtr(NULL, 0),
+	iCbwBufPtr(NULL,0)
+	{
+	__FNLOG("CBulkOnlyTransport::CBulkOnlyTransport");
+	}
+
+/**
+Destructor
+*/
+CBulkOnlyTransport::~CBulkOnlyTransport()
+	{
+	__FNLOG("CBulkOnlyTransport::~CBulkOnlyTransport");
+	if (iInterfaceConfigured)
+		{
+		Stop();
+		}
+	}
+
+
+/**
+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(TUint aLength)
+	{
+	__FNLOG("CBulkOnlyTransport::SetupReadData");
+	__PRINT1(_L("Length = %d  (bytes)\n"), aLength);
+	iBufSize = aLength;
+	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)
+	{
+	__FNLOG("CBulkOnlyTransport::SetupWriteData");
+	__PRINT1(_L("Length = %d  (bytes)\n"), aData.Length());
+	iWriteBufPtr.Set(aData);
+	iWriteSetUp = ETrue;
+	}
+
+
+TInt CBulkOnlyTransport::Start()
+	{
+	__FNLOG("CBulkOnlyTransport::Start");
+
+	TInt err = KErrNone;
+
+	if (!iProtocol)
+		{
+		return KErrBadHandle;   //protocol should be set up before start
+		}
+
+	if (IsActive())
+		{
+		__PRINT(_L("CBulkOnlyTransport::Start  - active before start!\n"));
+		return KErrInUse;
+		}
+
+	if ((err = SetupConfigurationDescriptor()) 	!= KErrNone ||
+		(err = SetupInterfaceDescriptors())		!= KErrNone )
+		{
+		__PRINT(_L("CBulkOnlyTransport::Start  - Error during descriptors setup!\n"));
+		return err;
+		}
+
+	AllocateEndpointResources();
+	ActivateDeviceStateNotifier();  // activate notifier wich will wait until USB became configured
+	TUsbcDeviceState deviceStatus = EUsbcDeviceStateDefault;
+	err = GetDeviceStatus(deviceStatus);
+	__PRINT1(_L("CBulkOnlyTransport::Start - Device status = %d\n"), deviceStatus);
+	if (err == KErrNone && deviceStatus == EUsbcDeviceStateConfigured)
+		{
+		__PRINT(_L("CBulkOnlyTransport::Start  - Starting bulk only transport\n"));
+		err = HwStart();
+		}
+
+#ifdef MSDC_MULTITHREADED
+	TPtr8 aDes1(NULL,0);
+	TPtr8 aDes2(NULL,0);
+	GetBufferPointers(aDes1, aDes2);
+	iProtocol->InitializeBufferPointers(aDes1, aDes2); // have to pass pointer to memory not offsets to initialise TPtr, and lengths
+#endif
+
+	iInterfaceConfigured = ETrue;
+	return err;
+	}
+
+TInt CBulkOnlyTransport::HwStart(TBool aDiscard)
+	{
+	__FNLOG("CBulkOnlyTransport::HwStart");
+
+    TInt lun = MaxLun();
+    do
+        {
+        Controller().DriveManager().Connect(lun);
+        }
+    while(--lun >= 0);
+
+	TInt res = StartControlInterface();
+
+	iCurrentState = ENone;
+	iWriteSetUp=EFalse;
+	iReadSetUp=EFalse;
+	iStarted = ETrue;
+
+    if (aDiscard)
+		{
+		FlushData();
+		}
+
+	ReadCBW();
+	return res;
+	}
+
+
+TInt CBulkOnlyTransport::HwStop()
+	{
+	__FNLOG("CBulkOnlyTransport::HwStop");
+	if (iStarted)
+		{
+        StopBulkOnlyEndpoint();
+		CancelControlInterface();
+		iStarted = EFalse;
+		}
+	return KErrNone;
+	}
+
+
+void CBulkOnlyTransport::StopBulkOnlyEndpoint()
+	{
+	__FNLOG("CBulkOnlyTransport::StopBulkOnlyEndpoint");
+
+    TInt lun = MaxLun();
+    do
+        {
+        Controller().DriveManager().Disconnect(lun);
+        }
+    while(--lun >= 0);
+	Cancel();
+	iProtocol->Cancel();
+	}
+
+
+TInt CBulkOnlyTransport::HwSuspend()
+	{
+	__FNLOG("CBulkOnlyTransport::HwSuspend");
+
+	TInt lun = MaxLun();
+	do
+		{
+		Controller().DriveManager().Disconnect(lun);
+		}
+	while(--lun >= 0);
+
+	return KErrNone;
+	}
+
+
+TInt CBulkOnlyTransport::HwResume()
+	{
+	__FNLOG("CBulkOnlyTransport::HwResume");
+
+    TInt lun = MaxLun();
+    do
+        {
+        Controller().DriveManager().Connect(lun);
+        }
+    while(--lun >= 0);
+
+	return KErrNone;
+	}
+
+/**
+Stops the Bulk Only Transport
+*/
+TInt CBulkOnlyTransport::Stop()
+	{
+	__FNLOG("CBulkOnlyTransport::Stop");
+	CancelControlInterface();
+	CancelDeviceStateNotifier();
+	Cancel();
+	if  (iInterfaceConfigured)
+		{
+		ReleaseInterface();
+		SetupConfigurationDescriptor(ETrue);
+		}
+	iCurrentState = ENone;
+	iInterfaceConfigured = EFalse;
+
+	return KErrNone;
+	}
+
+
+
+void CBulkOnlyTransport::DoCancel()
+	{
+	__FNLOG("CBulkOnlyTransport::DoCancel");
+	CancelReadWriteRequests();
+	}
+
+
+void CBulkOnlyTransport::Activate(TInt aReason)
+    {
+    SetActive();
+    TRequestStatus* r = &iStatus;
+    User::RequestComplete(r, aReason);
+    }
+
+
+void CBulkOnlyTransport::RunL()
+	{
+	__FNLOG("CBulkOnlyTransport::RunL");
+	if (iStatus != KErrNone)
+		{
+		__PRINT1(_L("Error %d in RunL, halt endpoints \n"), iStatus.Int());
+		SetPermError(); //halt endpoints for reset recovery
+		return;
+		}
+	switch (iCurrentState)
+		{
+		case EWaitForCBW:
+			__PRINT(_L("EWaitForCBW"));
+			ProcessCbwEvent();
+			break;
+
+		case EWritingData:
+            __PRINT(_L("EWritingData"));
+			iWriteSetUp = EFalse;  //the buffer was used
+
+			if (iDataResidue && iStallAllowed)
+				{
+				StallEndpointAndWaitForClear();
+				}
+
+			SendCSW(iCbwTag, iDataResidue, iCmdStatus);
+			break;
+
+		case EReadingData:
+			{
+			__PRINT(_L("EReadingData"));
+
+			ProcessReadingDataEvent();
+			}
+			break;
+
+		case ESendingCSW:
+			__PRINT(_L("ESendingCSW"));
+			ReadCBW();
+			break;
+
+        case EPermErr:
+			__PRINT(_L("EPermErr"));
+			StallEndpointAndWaitForClear();
+            break;
+
+        default:
+			SetPermError();		// unexpected state
+		}
+	}
+
+
+/**
+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()
+	{
+	__FNLOG("CBulkOnlyTransport::DecodeCBW");
+
+	SetCbwPtr();
+
+	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();
+		ExpireData((TAny*) (iCbwBufPtr.Ptr()));
+		return;
+		}
+
+	TPtrC8 aData;
+	aData.Set(&iCbwBufPtr[KCbwCbLengthOffset], KMaxCbwcbLength+1);    //prepare data for protocol starting form Length
+	TUint8 lun = static_cast<TUint8>(iCbwBufPtr[13] & 0x0f);
+
+	iCbwTag  =	static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset])		|
+				static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+1])	<<8 |
+				static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+2])	<<16|
+				static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+3])	<<24;
+
+	TInt i = KCbwDataTransferLengthOffset;
+	TUint hostDataLength = 	static_cast<TUint32>(iCbwBufPtr[i  ])		|
+							static_cast<TUint32>(iCbwBufPtr[i+1]) <<8 	|
+							static_cast<TUint32>(iCbwBufPtr[i+2]) <<16	|
+							static_cast<TUint32>(iCbwBufPtr[i+3]) <<24;
+
+	TBool dataToHost = iCbwBufPtr[KCbwFlagOffset] & 0x80;
+
+	__PRINT4(_L("lun =%d, hostDataLength=%d, CBWtag = 0x%x, dataToHost=%d\n"), lun, hostDataLength, iCbwTag, dataToHost);
+	//////////////////////////////////////////////
+	TBool ret = iProtocol->DecodePacket(aData, lun);
+	//////////////////////////////////////////////
+	ExpireData((TAny*) (iCbwBufPtr.Ptr()));
+
+
+	iStallAllowed = ETrue;
+
+	if (!ret)
+		{
+		__PRINT(_L("Command Failed\n"));
+		iCmdStatus = ECommandFailed;
+		}
+	else
+		{
+		__PRINT(_L("Command Passed\n"));
+		iCmdStatus = ECommandPassed;
+		}
+
+	if (hostDataLength)    // Host  expected data transfer
+		{
+		if (dataToHost)  // send data to host
+			{
+			if (!iWriteSetUp) //write buffer was not set up
+				{
+				__PRINT(_L("Write buffer was not setup\n"));
+				iDataResidue =hostDataLength;
+				__PRINT1(_L("DataResidue (write to host)=%d\n"),iDataResidue);
+
+//------------------------------------
+				if (hostDataLength <= KBOTMaxBufSize)
+					{
+					__PRINT(_L("Case 4 or 8\n"));
+					SetPaddingBufPtr(hostDataLength);
+					iPaddingBufPtr.FillZ(hostDataLength);
+					TPtrC8 ptr(NULL, 0);
+					ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), hostDataLength);
+					WriteData(iStatus, ptr, hostDataLength, EFalse);
+					iStallAllowed = EFalse;
+					if (iReadSetUp)  //read buffer WAS set up - case (8)
+						{
+						__PRINT(_L("It is Case 8\n"));
+						iCmdStatus = EPhaseError;
+						}
+					return;
+					}
+				else
+//------------------------------------
+//					Use next block instead of StallEndpointAndWaitForClear(InEndpoint);
+					{
+					SetPaddingBufPtr(hostDataLength);
+					iPaddingBufPtr.FillZ(KBOTMaxBufSize);
+					TUint c =0;
+					TRequestStatus status;
+					while (c<hostDataLength)
+						{
+						TInt len;
+						if (hostDataLength - c >  KBOTMaxBufSize)
+							{
+							len = KBOTMaxBufSize;
+							}
+						else
+							{
+							len = hostDataLength - c;
+							}
+
+							TPtrC8 ptr(NULL, 0);
+							ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), len);
+							WriteUsb(status, ptr, len);
+							User::WaitForRequest(status);
+							c +=  KBOTMaxBufSize;
+						}
+					}
+
+				if (iReadSetUp)  //read buffer WAS set up - case (8)
+					{
+					__PRINT(_L("Case 8\n"));
+					SendCSW(iCbwTag, hostDataLength, EPhaseError);
+					  //don't care to reset any flag - should get reset recovery
+					}
+				else   // case (4)
+					{
+					__PRINT(_L("Case 4\n"));
+					SendCSW(iCbwTag, hostDataLength, iCmdStatus);
+					}
+				return;
+				}	// if (!iWriteSetUp)
+
+//==================
+			TUint deviceDataLength = static_cast<TUint>(iWriteBufPtr.Length());
+			iDataResidue =hostDataLength - deviceDataLength ;
+			__PRINT2(_L("Device data length = %d, DataResidue (write to host)=%d\n"), deviceDataLength, iDataResidue);
+
+			if (deviceDataLength < hostDataLength  &&
+				hostDataLength < KBOTMaxBufSize )
+					{
+					__PRINT(_L("Case 5 (padding)\n"));
+					SetPaddingBufPtr(hostDataLength);
+					iPaddingBufPtr.Zero();
+					iPaddingBufPtr.Append(iWriteBufPtr);
+					iStallAllowed = EFalse;
+					__PRINT1(_L("iPaddingBufPtr.Length = %d\n"),iPaddingBufPtr.Length());
+					TPtrC8 ptr(NULL, 0);
+					ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), hostDataLength);
+					WriteData(iStatus, ptr, hostDataLength, EFalse);
+					return;
+					}
+
+//===================
+
+			if (deviceDataLength == hostDataLength)  	//case (6)[==]
+				{
+				__PRINT(_L("Case 6\n"));
+				WriteData(iStatus, iWriteBufPtr, deviceDataLength);
+				return;
+				}
+			else if (deviceDataLength < hostDataLength)	//case (5)[<]
+				{
+				__PRINT(_L("Case 5\n"));
+				WriteData(iStatus, iWriteBufPtr, deviceDataLength, ETrue);		// Send ZLP
+				return;
+				}
+			else 										// deviceDataLength > hostDataLength - case (7)
+				{
+				__PRINT(_L("Case 7\n"));
+				iCmdStatus = EPhaseError;
+				iDataResidue = 0;
+				WriteData(iStatus, iWriteBufPtr, hostDataLength);
+				return;
+				}
+			}
+		else  //read data from host
+			{
+			if (!iReadSetUp)
+				{
+				iDataResidue = hostDataLength;
+				__PRINT(_L("Read buffer was not setup\n"));
+//				Use next block instead of StallEndpointAndWaitForClear(OutEndpoint);
+				DiscardData(hostDataLength);
+
+				if (iWriteSetUp) //case (10)
+					{
+					__PRINT(_L("case 10\n"));
+					SendCSW(iCbwTag, hostDataLength, EPhaseError);
+					}
+				else // case (9)
+					{
+					__PRINT(_L("Case 9\n"));
+					SendCSW(iCbwTag, hostDataLength, iCmdStatus);
+					}
+
+				return;
+				}
+
+			TUint deviceDataLength = iBufSize;
+			iDataResidue = hostDataLength;  // calculate residue later
+
+			__PRINT2(_L("deviceDataLength = iBufSize = %d, DataResidue = HDL for now (read from host) =%d\n"),deviceDataLength,iDataResidue);
+
+			if (deviceDataLength <= hostDataLength)  // case (11) and (12)
+				{
+				__PRINT(_L("Case 11 or 12\n"));
+				ReadData(deviceDataLength);
+				return;
+				}
+			if (deviceDataLength > hostDataLength) // case  (13)
+				{
+				__PRINT(_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)
+                    {
+					WriteToClient(hostDataLength);
+                    iReadSetUp = EFalse;
+                    }
+                SendCSW(iCbwTag, hostDataLength, EPhaseError);
+				return;
+				}
+			}
+		}
+	else  // Host expected no data transfer
+		{
+		__PRINT(_L("No data transfer expected\n"));
+		iDataResidue = 0;
+		if (iWriteSetUp || iReadSetUp)   // case (2) and (3)
+			{
+			__PRINT(_L("Case 2 or 3\n"));
+			SendCSW(iCbwTag, 0, EPhaseError);
+			}
+		else
+			{
+			__PRINT(_L("Case 1\n"));
+			SendCSW(iCbwTag, 0, iCmdStatus);  //case (1)
+			}
+		}
+	}
+
+
+/**
+Check if CBW Valid and Meaningful.
+
+@return ETrue if CBW is Valid and Meaningful, EFalse otherwise
+*/
+TBool CBulkOnlyTransport::CheckCBW()
+	{
+	__FNLOG("CBulkOnlyTransport::CheckCBW");
+
+    //
+    // Check valid
+    //
+
+    // Check length
+    if ((TUint) (iCbwBufPtr.Length()) != KCbwLength)
+        {
+		__PRINT2(_L("Bad length: %d != KCbwLength"), iCbwBufPtr.Length(), KCbwLength);
+		return EFalse;
+        }
+
+    // Check signature
+	TInt i = KCbwSignatureOffset;
+	if (iCbwBufPtr[i  ] != 0x55 ||         // CBW Singature from USB Bulk-Only Transport spec
+		iCbwBufPtr[i+1] != 0x53 ||
+		iCbwBufPtr[i+2] != 0x42 ||
+		iCbwBufPtr[i+3] != 0x43)
+		{
+		__PRINT(_L("Bad signature"));
+		__PRINT4(_L(" 0x%x, 0x%x, 0x%x, 0x%x \n"), iCbwBufPtr[i], iCbwBufPtr[i+1], iCbwBufPtr[i+2],iCbwBufPtr[i+3])
+		return EFalse;
+		}
+
+    //
+    // Check meaningful
+    //
+
+    // Check reserved bits ( must be zero )
+    if ((iCbwBufPtr[KCbwLunOffset] & 0xF0) || (iCbwBufPtr[KCbwCbLengthOffset] & 0xE0))
+		{
+		__PRINT(_L("Reserved bits not zero\n"));
+		return EFalse;
+		}
+
+	// check command block length
+	TInt cbwcbLength = iCbwBufPtr[KCbwCbLengthOffset] & 0x1F;
+	if (cbwcbLength >KMaxCbwcbLength)
+		{
+		__PRINT(_L("Incorrect block length\n"));
+		return EFalse;
+		}
+
+	//check LUN
+	TInt8 lun = static_cast<TUint8>(iCbwBufPtr[KCbwLunOffset] & 0x0f);
+	if (iMaxLun < lun)
+		{
+		__PRINT1(_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()
+	{
+	__FNLOG("CBulkOnlyTransport::SetPermError");
+    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(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired)
+	{
+	__FNLOG("CBulkOnlyTransport::WriteData");
+
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+		return;
+		}
+	WriteUsb(aStatus, aDes, aLength, aZlpRequired);
+	iCurrentState = EWritingData;
+	SetActive();
+	}
+
+
+/**
+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)
+	{
+	__FNLOG("CBulkOnlyTransport::SendCSW");
+	__PRINT2(_L("DataResidue = %d, Status = %d \n"), aDataResidue, aStatus);
+
+	if (IsActive())
+		{
+		__PRINT(_L("Still active\n"));
+		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
+		return;
+		}
+
+	SetCswBufPtr(KCswLength);
+	TInt i = KCswSingnatureOffset;
+	iCswBufPtr[i  ] = 0x55;   // CSW Singature from USB Bulk-Only Transport spec
+	iCswBufPtr[i+1] = 0x53;
+	iCswBufPtr[i+2] = 0x42;
+	iCswBufPtr[i+3] = 0x53;
+
+	i = KCswTagOffset;
+
+	iCswBufPtr[i  ] = static_cast<TUint8>((aTag & 0x000000FF));
+	iCswBufPtr[i+1] = static_cast<TUint8>((aTag & 0x0000FF00) >> 8);
+	iCswBufPtr[i+2] = static_cast<TUint8>((aTag & 0x00FF0000) >> 16);
+	iCswBufPtr[i+3] = static_cast<TUint8>((aTag & 0xFF000000) >> 24);
+
+	i = KCswDataResidueOffset;
+	iCswBufPtr[i  ] = static_cast<TUint8>((aDataResidue & 0x000000FF));
+	iCswBufPtr[i+1] = static_cast<TUint8>((aDataResidue & 0x0000FF00) >> 8);
+	iCswBufPtr[i+2] = static_cast<TUint8>((aDataResidue & 0x00FF0000) >> 16);
+	iCswBufPtr[i+3] = static_cast<TUint8>((aDataResidue & 0xFF000000) >> 24);
+
+	iCswBufPtr[KCswStatusOffset] = static_cast<TUint8>(aStatus);
+
+	TPtrC8 ptr(NULL, 0);
+	ptr.Set((const TUint8*)iCswBufPtr.Ptr(), KCswLength);
+
+	WriteUsb(iStatus, ptr, 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)
+	{
+	__FNLOG("CBulkOnlyTransport::RegisterProtocol");
+	iProtocol = &aProtocol;
+	}
+
+
+/**
+Used by CControlInterface
+
+@return reference to the controller which instantiate the CBulkOnlyTransport
+*/
+CUsbMassStorageController& 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;
+	}
+
+
+void CBulkOnlyTransport::GetCommandBufPtr(TPtr8& aDes, TUint aLength) // Set pointer to buffer of specified aLength for command
+	{
+	aDes.Set(SetCommandBufPtr(aLength));
+	}
+
+void CBulkOnlyTransport::GetReadDataBufPtr(TPtr8& aDes) // Set pointer to buffer into which data is to be read from drive (Read10)
+	{
+	aDes.Set(SetDataBufPtr());
+	}
+
+
+void CBulkOnlyTransport::GetWriteDataBufPtr(TPtrC8& aDes) // Set pointer to buffer from which data is to be written to drive (Write10)
+	{
+	aDes.Set(iReadBufPtr);
+	}
+
+#ifdef MSDC_MULTITHREADED
+void CBulkOnlyTransport::ProcessReadData(TAny* aAddress)
+	{
+	ExpireData(aAddress);
+	}
+#endif
+
+
+
+
+
+
+
+