mtptransports/mtpusbtransport/usbsic_imp/src/cmtpusbepbase.cpp
changeset 0 d0791faffa3f
child 12 523717cdb0ad
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mtptransports/mtpusbtransport/usbsic_imp/src/cmtpusbepbase.cpp	Tue Feb 02 01:11:40 2010 +0200
@@ -0,0 +1,1087 @@
+// Copyright (c) 2006-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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "cmtpusbconnection.h"
+#include "cmtpusbepbase.h"
+#include "mtpusbpanic.h"
+#include "cmtpusbcontainer.h"
+#include "mtpbuildoptions.hrh"
+#include "mtpusbprotocolconstants.h"
+#include <e32debug.h>
+
+const TUint KUSBHeaderSize = 12;
+#define UNUSED_VAR(a) (a)=(a)
+
+/**
+Destructor
+*/
+CMTPUsbEpBase::~CMTPUsbEpBase()
+    {
+    __FLOG(_L8("CMTPUsbEpBase::~CMTPUsbEpBase - Entry"));
+    Cancel();
+    iPacketBuffer.Close();
+    __FLOG(_L8("CMTPUsbEpBase::~CMTPUsbEpBase - Exit"));
+    __FLOG_CLOSE;
+    }
+    
+/**
+Provides the logical endpoint number of the endpoint.
+@return The logical endpoint number. 
+*/
+TEndpointNumber CMTPUsbEpBase::EndpointNumber() const
+    {
+    return iConnection.EndpointNumber(iId);
+    }
+    
+/**
+Provides the internal endpoint identifier of the endpoint.
+@return The internal endpoint identifier. 
+*/
+TUint CMTPUsbEpBase::Id() const
+    {
+    return iId;
+    }
+
+/**
+Constructor
+@param aId The internal endpoint identifier of the endpoint.
+@param aPriority the priority of the active object assigned. 
+@param aConnection MTP USB device class transport connection which controls 
+the endpoint.
+*/
+CMTPUsbEpBase::CMTPUsbEpBase(TUint aId, TPriority aPriority, CMTPUsbConnection& aConnection) :
+    CActive(aPriority),
+    iId(aId),
+    iReceiveChunkData(NULL, 0),
+    iReceiveData(NULL, 0),
+    iSendChunkData(NULL, 0),
+    iSendData(NULL, 0),
+    iIsFirstChunk(EFalse), 
+    iConnection(aConnection)
+    {
+    CActiveScheduler::Add(this);
+    }
+    
+/**
+Second phase constructor.
+*/
+#ifdef __FLOG_ACTIVE    
+void CMTPUsbEpBase::ConstructL(const TDesC8& aComponentName)
+#else
+void CMTPUsbEpBase::ConstructL()
+#endif
+    {
+    __FLOG_OPEN(KMTPSubsystem, aComponentName);
+    __FLOG(_L8("CMTPUsbEpBase::ConstructL - Entry"));
+    __FLOG(_L8("CMTPUsbEpBase::ConstructL - Exit"));
+    }
+    
+/**
+Sets the MaxPacketSize for the endpoint.
+@param aSize The maximum packet size.
+@leave One of the system wide error codes, if a processing failure occurs.
+*/
+void CMTPUsbEpBase::SetMaxPacketSizeL(TUint aSize)
+	{
+	__FLOG(_L8("CMTPUsbEpBase::SetMaxPacketSizeL - Entry"));
+	iPacketSizeMax = aSize;
+	__FLOG_VA((_L8("Endpoint %d maximum packetsize = %u"), iId, iPacketSizeMax));
+	// Allocate the packet buffer.
+    iPacketBuffer.ReAllocL(iPacketSizeMax);
+    __FLOG(_L8("CMTPUsbEpBase::SetMaxPacketSizeL - Exit"));
+	}    
+
+/**
+Creates a stall condition on the endpoint.
+*/  
+void CMTPUsbEpBase::Stall()
+    {
+    __FLOG(_L8("CMTPUsbEpBase::Stall - Entry"));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    Cancel();
+    RDevUsbcClient& ldd(Connection().Ldd());
+    const TEndpointNumber number(EndpointNumber());
+    TEndpointState state;
+    ldd.EndpointStatus(number, state);
+    __FLOG_VA((_L8("EndpointStatus = %d"), state));
+    if (state != EEndpointStateStalled)
+        {
+        __FLOG_VA((_L8("Halting endpoint = %d"), number));
+        ldd.HaltEndpoint(number);
+        }
+    SetStreamState(EStalled);
+    __FLOG(_L8("CMTPUsbEpBase::Stall - Exit"));
+    }
+
+/**
+Clears a stall condition on the endpoint.
+*/    
+void CMTPUsbEpBase::StallClear()
+    {
+    __FLOG(_L8("CMTPUsbEpBase::StallClear - Entry"));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    RDevUsbcClient& ldd(Connection().Ldd());
+    const TEndpointNumber number(EndpointNumber());
+    TEndpointState state;
+    ldd.EndpointStatus(number, state);
+    __FLOG_VA((_L8("EndpointStatus = %d"), state));
+    if (state != EEndpointStateNotStalled)
+        {
+        __FLOG_VA((_L8("Clearing halt on endpoint = %d"), number));
+        Connection().Ldd().ClearHaltEndpoint(number);
+        }
+    SetStreamState(EIdle);
+    __FLOG(_L8("CMTPUsbEpBase::StallClear - Exit"));
+    }
+
+/**
+Indicates whether the endpoint is currently in a stalled condition.
+@return ETrue if the endpoint is in a stalled condition, otherwise EFalse.
+*/
+TBool CMTPUsbEpBase::Stalled() const
+    {
+    return (iState == EStalled);
+    }
+
+/**
+Determines the relative order of the two endpoints based on their IDs. 
+@return Zero, if the two objects are equal; a negative value, if the first 
+endpoint's ID is less than the second, or; a positive value, if the first 
+endpoint's ID is greater than the second.
+*/    
+TInt CMTPUsbEpBase::LinearOrder(const CMTPUsbEpBase& aL, const CMTPUsbEpBase& aR)
+    {
+    return (aL.iId - aR.iId);
+    }
+    
+/**
+Provides the MTP USB device class transport connection which controls the 
+endpoint.
+@return The MTP USB device class transport connection. 
+*/
+CMTPUsbConnection& CMTPUsbEpBase::Connection() const
+    {
+    return iConnection;
+    }
+
+/**
+Forces the completion of a transfer in progress. This will
+reset the data streams without having to stall the endpoints.
+
+This is needed because Windows does not expect endpoints to 
+stall on error conditions.
+
+@param aReason error code describing the reason for cancelling.
+@leave Any of the system wide error codes.
+*/
+
+void CMTPUsbEpBase::CancelReceiveL(TInt aReason)
+	{
+	__FLOG(_L8("CMTPUsbEpBase::CancelReceiveL - Entry"));
+     
+    if (DataStreamDirection() == EReceivingState)
+	    {
+		__FLOG(_L8("Cancel in EReceivingState"));            
+	    // Cancel any outstanding request.
+    	Cancel();  
+
+        // Notify the connection and reset the receive data stream.
+        ResetReceiveDataStream();
+        ReceiveDataCompleteL(aReason, *iReceiveDataSink);
+        // Flush incoming data, otherwise device and PC may get out of sync
+        FlushRxDataL();
+	    }
+	    
+    __FLOG(_L8("CMTPUsbEpBase::CancelReceiveL - Exit"));	
+	}
+
+/**
+Forces the completion of a transfer in progress. This will
+reset the data streams without having to stall the endpoints.
+
+This is needed because Windows does not expect endpoints to 
+stall on error conditions.
+
+@param aReason error code describing the reason for cancelling.
+@leave Any of the system wide error codes.
+*/
+
+void CMTPUsbEpBase::CancelSendL(TInt aReason)
+	{
+	__FLOG(_L8("CMTPUsbEpBase::CancelSendL - Entry"));
+    
+	if (DataStreamDirection() == ESendingState)
+		{
+ 		__FLOG(_L8("Cancel in ESendingState"));
+ 		// Cancel any outstanding request.
+    	Cancel();  
+        // Notify the connection and reset the send data stream.
+        ResetSendDataStream();
+        SendDataCompleteL(aReason, *iSendDataSource);
+		}
+		
+	__FLOG(_L8("CMTPUsbEpBase::CancelSendL - Exit"));
+	}
+
+/**
+Initiates an asynchronous data receive sequence. 
+@param aSink The receive data sink buffer.
+@leave One of the system wide error codes, if a processing failure occurs.
+*/
+void CMTPUsbEpBase::ReceiveDataL(MMTPType& aSink)
+    {
+    __FLOG(_L8("CMTPUsbEpBase::ReceiveDataL - Entry"));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    if(iState != EIdle)
+      {
+    	Cancel();
+      }
+    
+
+    __ASSERT_DEBUG(iState == EIdle, Panic(EMTPUsbBadState));
+    
+    iReceiveDataSink    = &aSink;
+    iReceiveDataCommit  = iReceiveDataSink->CommitRequired();
+    SetStreamState(EReceiveInitialising);
+    InitiateFirstChunkReceiveL(); 
+        
+    __FLOG_VA((_L8("CMTPUsbEpBase state on exit = 0x%08X"), iState));
+    __FLOG(_L8("CMTPUsbEpBase::ReceiveDataL - Exit")); 
+    }
+
+/**
+Resumes a halted data receive sequence.
+@param aSink The receive data sink buffer.
+@leave One of the system wide error codes, if a processing failure occurs.
+*/
+
+void CMTPUsbEpBase::ResumeReceiveDataL(MMTPType& aSink)
+	{
+	__FLOG(_L8("CMTPUsbEpBase::ResumeReceiveDataL - Entry"));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    __ASSERT_DEBUG(iState == EIdle, Panic(EMTPUsbBadState));
+    
+    iReceiveDataSink    = &aSink;
+    iReceiveDataCommit  = iReceiveDataSink->CommitRequired();
+    
+    iChunkStatus = iReceiveDataSink->NextWriteChunk(iReceiveChunkData);
+    // The first chunk is going to be read.
+    iReceiveData.Set(iReceiveChunkData);
+    __FLOG_VA((_L8("Issuing ReadUntilShort request on endpoint %d"), EndpointNumber()));
+    __FLOG_VA((_L8("Receive chunk capacity = %d bytes, length = %d bytes"), iReceiveChunkData.MaxLength(), iReceiveChunkData.Length()));
+    __FLOG_VA((_L8("Chunk status = %d"), iChunkStatus)); 
+    Connection().Ldd().ReadUntilShort(iStatus, EndpointNumber(), iReceiveData);
+    SetStreamState(EReceiveInProgress);
+    SetActive();
+    __FLOG(_L8("CMTPUsbEpBase::ResumeReceiveDataL - Exit")); 
+	}
+
+/**
+Signals the data transfer controller that an asynchronous data receive 
+sequence has completed.
+@leave One of the system wide error codes, if a processing failure occurs.
+@panic MTPUsb 2 In debug builds only, if the derived class has not fully 
+implemented the receive data path.
+*/
+void CMTPUsbEpBase::ReceiveDataCompleteL(TInt /*aError*/, MMTPType& /*aSink*/)
+    {
+    __FLOG(_L8("CMTPUsbEpBase::ReceiveDataCompleteL - Entry"));
+    __DEBUG_ONLY(Panic(EMTPUsbNotSupported));
+    __FLOG(_L8("CMTPUsbEpBase::ReceiveDataCompleteL - Exit"));
+    }
+
+/**
+Initiates an asynchronous data send sequence. 
+@param aSource The send data source buffer.
+@leave One of the system wide error codes, if a processing failure occurs.
+*/
+void CMTPUsbEpBase::SendDataL(const MMTPType& aSource)
+    {
+    __FLOG(_L8("CMTPUsbEpBase::SendDataL - Entry"));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    __ASSERT_DEBUG(iState == EIdle, Panic(EMTPUsbBadState));
+    
+    iSendDataSource = &aSource;
+    SetStreamState(ESendInitialising);
+    ProcessSendDataStreamL();
+        
+    __FLOG_VA((_L8("CMTPUsbEpBase state on exit = 0x%08X"), iState));
+    __FLOG(_L8("CMTPUsbEpBase::SendDataL - Exit"));
+    }
+
+/**
+Signals tthe data transfer controller that an asynchronous data send sequence 
+has completed.
+@leave One of the system wide error codes, if a processing failure occurs.
+@panic MTPUsb 2 In debug builds only, if the derived class has not fully 
+implemented the send data path.
+*/
+void CMTPUsbEpBase::SendDataCompleteL(TInt /*aError*/, const MMTPType& /*aSource*/)
+    {
+    __FLOG(_L8("CMTPUsbEpBase::SendDataCompleteL - Entry"));
+    __DEBUG_ONLY(Panic(EMTPUsbNotSupported));
+    __FLOG(_L8("CMTPUsbEpBase::SendDataCompleteL - Exit"));
+    }
+
+void CMTPUsbEpBase::DoCancel()
+    {
+    __FLOG(_L8("CMTPUsbEpBase::DoCancel - Entry"));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    switch (iState & EStateDirection)
+        {
+    case EReceivingState:
+        __FLOG_VA((_L8("Issuing ReadCancel on endpoint %d"), EndpointNumber()));
+        Connection().Ldd().ReadCancel(EndpointNumber());
+        ResetReceiveDataStream();
+        break;
+
+    case ESendingState:    
+        __FLOG_VA((_L8("Issuing WriteCancel on endpoint %d"), EndpointNumber()));
+        Connection().Ldd().WriteCancel(EndpointNumber());
+        ResetSendDataStream();
+        break;
+
+    default:
+        break;
+        }
+    __FLOG(_L8("CMTPUsbEpBase::DoCancel - Exit"));
+    }
+    
+TInt CMTPUsbEpBase::RunError(TInt aError)
+    {
+    __FLOG(_L8("CMTPUsbEpBase::RunError - Entry"));
+    __FLOG_VA((_L8("Error = %d"), aError));  
+    
+    // Cancel any outstanding request.
+    Cancel();  
+    
+    // Notify the protocol layer of the error.
+    TInt32 streamDirection = DataStreamDirection();
+    if (streamDirection == EReceivingState)
+	    {
+		__FLOG(_L8("Error in EReceivingState"));            
+        // Notify the connection and reset the receive data stream.
+        MMTPType& data(*iReceiveDataSink);
+        ResetReceiveDataStream();
+        TRAPD(err, ReceiveDataCompleteL(aError, data));
+        UNUSED_VAR(err);
+	    }
+	else if (streamDirection == ESendingState)
+		{
+		__FLOG(_L8("Error in ESendingState"));
+        // Notify the connection and reset the send data stream.
+        const MMTPType& data(*iSendDataSource);
+        ResetSendDataStream();
+        TRAPD(err, SendDataCompleteL(aError, data));
+        UNUSED_VAR(err);
+		}
+	    
+    __FLOG(_L8("CMTPUsbEpBase::RunError - Exit"));
+    return KErrNone;
+    }
+
+void CMTPUsbEpBase::RunL()
+    {
+    __FLOG(_L8("CMTPUsbEpBase::RunL - Entry"));
+    __FLOG_VA((_L8("Current endpoint is %d"), EndpointNumber()));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    
+    switch (DataStreamDirection())
+        {
+    case EReceivingState:
+        __FLOG_VA((_L8("Receive data completion status = %d"), iStatus.Int()));
+        if (iStatus != KErrNone)
+            {
+            // Abnormal completion.
+            SetStreamState(EReceiveComplete);
+            }
+        else
+            {
+            // Reissue the request if we got a null packet because the upper layers are not 
+        	// interested in null packets.
+        	if ((iReceiveData.Length() == 0) && (iReceiveData.MaxLength() > 0))
+        		{
+        		Connection().Ldd().ReadUntilShort(iStatus, EndpointNumber(), iReceiveData);
+        		SetActive();
+        		return;
+        		}  
+            // Update the chunk data length.
+            iReceiveChunkData.SetLength(iReceiveChunkData.Length() + iReceiveData.Length());
+            if (iIsFirstChunk)
+	            {
+	            // process the first chunk.
+	            ProcessFirstReceivedChunkL();  
+	            }
+	        else
+		        {
+		        ResumeReceiveDataStreamL(); 
+		        }
+            }
+            
+        if (iState == EReceiveComplete)
+            {
+            // Reset the receive data stream and notify the connection.
+            MMTPType& data(*iReceiveDataSink);
+            ResetReceiveDataStream();
+            ReceiveDataCompleteL(iStatus.Int(), data);
+            }
+        break;
+        
+    case ESendingState:   
+        __FLOG_VA((_L8("Send data stream completion status = %d"), iStatus.Int())); 
+        if (iStatus != KErrNone)
+            {
+            // Abnormal completion.
+            SetStreamState(ESendComplete);
+            }
+        else
+            {
+            ProcessSendDataStreamL(); 
+            }
+            
+        if (iState == ESendComplete)
+            {
+            // Reset the send data stream and notify the connection.
+            const MMTPType& data(*iSendDataSource);
+            ResetSendDataStream();
+            SendDataCompleteL(iStatus.Int(), data);
+            }
+        break;
+        
+    default:
+        __FLOG_VA((_L8("Invalid data stream state, status = %d"), iStatus.Int())); 
+        Panic(EMTPUsbBadState);
+        break;
+        }
+        
+    __FLOG_VA((_L8("IsActive = %d"), IsActive()));
+    __FLOG(_L8("CMTPUsbEpBase::RunL - Exit"));
+    }
+
+/**
+Provides the current data stream direction.
+@return The current data stream direction (EIdle, EReceivingState, or 
+ESendingState).
+@see TState.
+*/
+TInt32 CMTPUsbEpBase::DataStreamDirection() const
+    {
+    return (iState & EStateDirection);
+    }
+
+/**
+Resets the receive data stream by clearing all receive buffer pointers and
+setting the stream state to EIdle.
+*/    
+void CMTPUsbEpBase::ResetReceiveDataStream()
+    {
+	__FLOG(_L8("CMTPUsbEpBase::ResetReceiveDataStream - Entry"));
+    iReceiveChunkData.Set(NULL, 0, 0);
+    iReceiveData.Set(NULL, 0, 0);
+    iReceiveDataSink = NULL;
+    SetStreamState(EIdle);
+	__FLOG(_L8("CMTPUsbEpBase::ResetReceiveDataStream - Exit"));
+    }
+
+/**
+Resets the receive data stream by clearing all receive buffer pointers and
+setting the stream state to EIdle.
+*/    
+void CMTPUsbEpBase::ResetSendDataStream()
+    {
+	__FLOG(_L8("CMTPUsbEpBase::ResetSendDataStream - Entry"));
+    iSendChunkData.Set(NULL, 0);
+    iSendData.Set(NULL, 0);
+    iSendDataSource = NULL;
+    SetStreamState(EIdle);
+	__FLOG(_L8("CMTPUsbEpBase::ResetSendDataStream - Exit"));
+    }
+    
+/**
+This method verify if the received first chunk data is a valid
+USB header for BulkOut EP.
+@pre this method should only be called after the USB header is received.
+@return ETrue if the received first chunk data is a vaild USB header, otherwise EFalse.
+*/
+TBool CMTPUsbEpBase::ValidateUSBHeaderL()
+	{	
+	__FLOG(_L8("CMTPUsbEpBase::ValidateUSBHeader - Entry"));
+	
+	TBool result(EFalse);
+	TUint16 containerType(Connection().BulkContainer().Uint16L(CMTPUsbContainer::EContainerType));
+	iDataLength = Connection().BulkContainer().Uint32L(CMTPUsbContainer::EContainerLength);
+	
+	//Due to an issue of Windows OS, the value of CMTPUsbContainer::EContainerLength is incorrect if the
+	//object >= 4G-12. The value should be KMaxTUint32 in this kind of cases, but in current Windows
+	//implementation it will be a value between 0 and 11.
+	//Here we reset the iDateLength to the actual size of iReceiveDataSink as a walkaround.
+	if(containerType == 2 && (iDataLength <= 11 || iDataLength == KMaxTUint32))
+		{
+		__FLOG(_L8("iDataLength <= 11, change to size of receive data sink"));			
+		iDataLength = iReceiveDataSink->Size();
+		}
+	
+	__FLOG_VA((_L8("containerType = %u , dataLength = %lu bytes"), containerType, iDataLength));
+	
+	if (iDataLength >= KUSBHeaderSize && 
+		(containerType == EMTPUsbContainerTypeCommandBlock || containerType == EMTPUsbContainerTypeDataBlock))
+		{
+		result = ETrue;
+		iDataCounter = 0;
+#ifdef _DEBUG
+ 		RDebug::Print(_L("Find the valid usb header------------------------------------------------------\n"));
+ 		TUint16 code(Connection().BulkContainer().Uint16L(CMTPUsbContainer::ECode));
+ 		TUint32 transactionID(Connection().BulkContainer().Uint32L(CMTPUsbContainer::ETransactionID));
+ 		RDebug::Print(_L("ContainerLength = 0x%x, containerType = 0x%x , code = 0x%x , transactionID = 0x%x "),  iDataLength, containerType, code, transactionID);
+ 		}
+ 	else
+ 		{
+ 		RDebug::Print(_L("inValid usb Header read..........................................................."));
+#endif
+ 		}
+	__FLOG(_L8("CMTPUsbEpBase::ValidateUSBHeader - Exit"));
+	return result;
+	}
+
+/**
+Initiates the first chunk received data.
+*/
+void CMTPUsbEpBase::InitiateFirstChunkReceiveL()
+	{
+	__FLOG(_L8("CMTPUsbEpBase::InitiateFirstChunkReceiveL - Entry"));
+	
+	__FLOG(_L8("Fetching first write data chunk"));
+    iChunkStatus = iReceiveDataSink->FirstWriteChunk(iReceiveChunkData);
+    // The first chunk is going to be read.
+    iIsFirstChunk = ETrue;
+    iReceiveData.Set(iReceiveChunkData);
+    __FLOG_VA((_L8("Issuing ReadUntilShort request on endpoint %d"), EndpointNumber()));
+    __FLOG_VA((_L8("Receive chunk capacity = %d bytes, length = %d bytes"), iReceiveChunkData.MaxLength(), iReceiveChunkData.Length()));
+    __FLOG_VA((_L8("Chunk status = %d"), iChunkStatus)); 
+    Connection().Ldd().ReadUntilShort(iStatus, EndpointNumber(), iReceiveData);
+    SetStreamState(EReceiveInProgress);
+    SetActive();
+    
+    __FLOG(_L8("Request issued"));
+	__FLOG(_L8("CMTPUsbEpBase::InitiateFirstChunkReceiveL - Exit"));
+	}
+	
+/**
+Processes the first received chunk data.
+*/
+void CMTPUsbEpBase::ProcessFirstReceivedChunkL()
+	{
+	__FLOG(_L8("CMTPUsbEpBase::ProcessFirstReceivedChunkL - Entry"));	
+	    
+    // Reset it back.
+    iIsFirstChunk = EFalse;
+        
+    if (iReceiveChunkData.MaxLength() == KUSBHeaderSize
+      && iReceiveChunkData.Length() == KUSBHeaderSize)
+	    {
+	    // USB header received from BulkOut EP.
+	    // USB Header validation
+	    if (!ValidateUSBHeaderL())
+		    {
+			// If device has received trash data, flush the rest of the packet and try again.
+  	  	 	// This will occur when cancelling a transfer and the PC sends buffered data after 
+  	  	 	// the cancellation.
+		    TRequestStatus status;
+  	  		do
+				{
+				// Keep looking for headers.
+				// The case we are trying to catch is when we have 12 garbage bytes followed by 12 good bytes.
+				// In this case the ReadOneOrMore is acting on the next packet rather than the current packet.
+				// If the garbage data is a multiple of 12 bytes, we should still be able to catch the next good
+				// header. Otherwise the ReadOneOrMore will return will <12 bytes and we will fall through
+				// to the retry code below. 
+				iReceiveData.Zero();
+				Connection().Ldd().ReadOneOrMore(status, EndpointNumber(), iReceiveData, KUSBHeaderSize);
+				User::WaitForRequest(status);
+				} while (iReceiveData.Length()==KUSBHeaderSize && !ValidateUSBHeaderL());
+
+			if(!ValidateUSBHeaderL())
+				{ 
+				InitiateFirstChunkReceiveL();  
+				return;
+				}
+			}
+			
+		if ((iDataLength - KUSBHeaderSize) == 0)
+			{
+			// only USB header.
+			SetStreamState(EReceiveComplete);
+			}	        
+	    }
+     else if (iReceiveChunkData.MaxLength() == iReceiveChunkData.Length())
+		{
+		// USB Control request setup or data packet is received from Control EP.		    		    		    
+	    // All the desired data should be received. 
+		SetStreamState(EReceiveComplete);			
+		}
+		
+	__FLOG_VA((_L8("CMTPUsbEpBase state = 0x%08X"), iState));
+	
+	if (iState == EReceiveComplete)
+		{
+		// All data is received just using the first chunk. It could be a USB Command block without parameters
+		// or USB control request setup or data. 
+		__FLOG_VA((_L8("Received = %d bytes, write data chunk capacity = %d bytes"), iReceiveChunkData.Length(), iReceiveChunkData.MaxLength()));
+		
+#ifdef MTP_DEBUG_FLOG_HEX_DUMP 
+        __FLOG_HEXDUMP((iReceiveChunkData, _L8("Received data ")));
+#endif
+
+		// Commit the received data if required.
+        if (iReceiveDataCommit)
+		    {
+		 	__FLOG(_L8("Commiting write data chunk"));
+	        iReceiveDataSink->CommitChunkL(iReceiveChunkData);       
+		    }
+		}
+	// Receive more data.
+	else
+		{
+		ResumeReceiveDataStreamL();
+		}
+	
+	__FLOG(_L8("CMTPUsbEpBase::ProcessFirstReceivedChunkL - Exit"));
+	}
+
+/**
+Implements the receive data streaming algorithm. It is called after the first chunk data is received provided
+there is still more data to be received. 
+*/
+void CMTPUsbEpBase::ResumeReceiveDataStreamL()
+    {
+    __FLOG(_L8("CMTPUsbEpBase::ResumeReceiveDataStreamL - Entry"));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    TBool endStream(EFalse);
+	TBool lastChunkCommited(EFalse);
+	TBool nullPacketReceived(EFalse);
+	MMTPType *needCommit = NULL;
+    // Process the received chunk (if any).
+   	iDataCounter += iReceiveData.Length();
+   	__FLOG_VA((_L8("iDataLength = %lu bytes"), iDataLength));
+   	__FLOG_VA((_L8("iDataCounter = %lu bytes"), iDataCounter));   	
+   	
+   	if (iDataCounter == iDataLength)
+	   	{
+	   	endStream = ETrue;
+        nullPacketReceived = ((iState == EReceiveCompleting) && (iReceiveData.Length() == 0));
+	   	}
+
+    __FLOG_VA((_L8("Received = %d bytes, write data chunk capacity = %d bytes"), iReceiveChunkData.Length(), iReceiveChunkData.MaxLength()));		   
+#ifdef MTP_DEBUG_FLOG_HEX_DUMP 
+    __FLOG_HEXDUMP((iReceiveChunkData, _L8("Received data ")));
+#endif
+    __FLOG_VA((_L8("End of stream = %d"), endStream)); 		   
+        
+      // Commit the received data if required.
+	if (iReceiveDataCommit)
+         {
+         if ((iChunkStatus != KMTPChunkSequenceCompletion)
+       		&& !endStream
+          	&& (iReceiveChunkData.Length() == iReceiveChunkData.MaxLength()))
+	           {
+	           	// Two cases are covered here:
+	           	// 1. MTP file receiving: MTP type file never returns KMTPChunkSequenceCompletion,It can be received        
+          		//    one part after another. Also it can be commited mutiple times.
+            	// 2. Other MTP datatype receiving during the middle of data stream
+	           __FLOG(_L8("Commiting write data chunk"));
+	           needCommit = iReceiveDataSink->CommitChunkL(iReceiveChunkData);
+	           lastChunkCommited = ETrue;   
+	           }
+		else if ((iChunkStatus != KMTPChunkSequenceCompletion)
+	        	&& endStream
+	        	&& !nullPacketReceived)
+		      {
+		      // It should be the end of MTP type file receiving since it never returns KMTPChunkSequenceCompletion.
+	 	      // it can be commited mutiple times.
+		      __FLOG(_L8("Commiting write data chunk"));
+		      needCommit = iReceiveDataSink->CommitChunkL(iReceiveChunkData);
+		      }
+		else if ((iChunkStatus == KMTPChunkSequenceCompletion)
+	        	&& endStream
+	        	&& !nullPacketReceived)
+		      {
+		      // The last chunk data which type is any other MTP data type than MTP file type. 
+		      // It will not be commited until all the chunk data is received.
+		      __FLOG(_L8("Commiting write data chunk"));
+		      needCommit = iReceiveDataSink->CommitChunkL(iReceiveChunkData); 
+		      }          
+         }  
+
+    // Fetch the next read data chunk.  
+    switch (iState)
+        {
+    case EReceiveInProgress:
+    	if (iReceiveDataCommit) // Commiting the received data is required 
+		    {
+		    if (lastChunkCommited)
+			    {
+			    __FLOG(_L8("Fetching next write data chunk"));
+	    	 	iChunkStatus = iReceiveDataSink->NextWriteChunk(iReceiveChunkData, iDataLength - KUSBHeaderSize);
+			    }
+		    }
+		else
+			{
+			__FLOG(_L8("Fetching next write data chunk"));
+    	 	iChunkStatus = iReceiveDataSink->NextWriteChunk(iReceiveChunkData, iDataLength - KUSBHeaderSize);	
+			}	         		    					      
+        break;
+        
+    case EReceiveCompleting:
+        __FLOG(_L8("Write data chunk sequence completing"));
+        __FLOG_VA((_L8("Null packet received = %d"), nullPacketReceived)); 
+        break;
+                  
+    case EIdle:
+    default:
+        __FLOG(_L8("Invalid receive data stream state"));
+        Panic(EMTPUsbBadState);
+        break;
+        }
+    __FLOG_VA((_L8("Chunk status = %d"), iChunkStatus)); 
+        
+    // Update the data stream state.
+    switch (iChunkStatus)
+        {
+    case KErrNone:
+        if (endStream)
+            {
+            __FLOG(_L8("Terminating packet received."));
+            SetStreamState(EReceiveComplete);
+            }
+        else
+            {
+            // Full (intermediate) packet data received.
+            SetStreamState(EReceiveInProgress);
+            }
+        break;
+        
+    case KMTPChunkSequenceCompletion:
+
+        if (endStream)
+            {
+            __FLOG(_L8("Terminating packet received."));
+            SetStreamState(EReceiveComplete);
+            }
+        else
+            {           
+            // Processing the last received data chunk.
+            // It will be processed once or mutiple times. 
+            SetStreamState(EReceiveCompleting);            
+            }
+        break;
+        
+    default:
+        User::Leave(iChunkStatus);
+        break;
+        } 
+        
+    // If necessary, process the next chunk. 
+    if (iState != EReceiveComplete)
+        {
+        __FLOG_VA((_L8("Issuing ReadUntilShort request on endpoint %d"), EndpointNumber()));
+        __FLOG_VA((_L8("Receive chunk capacity = %d bytes, length = %d bytes"), iReceiveChunkData.MaxLength(), iReceiveChunkData.Length()));
+        __FLOG_VA((_L8("iReceiveChunkData pointer address is %08x"), iReceiveChunkData.Ptr()));
+        // TDesC8's Right() method is not used here, because the parameter passed in like iReceiveChunkData.MaxLength() - iReceiveChunkData.Length()is greater than 
+        // the length of the descriptor, the function extracts the whole of the descriptor.
+        if(iDataLength-iDataCounter < iReceiveChunkData.MaxLength() - iReceiveChunkData.Length())
+			{
+			iReceiveData.Set(const_cast<TUint8*>(iReceiveChunkData.Ptr() + iReceiveChunkData.Length()), 0, iDataLength - iDataCounter);
+			}
+		else
+			{
+			iReceiveData.Set(const_cast<TUint8*>(iReceiveChunkData.Ptr() + iReceiveChunkData.Length()), 0, iReceiveChunkData.MaxLength() - iReceiveChunkData.Length());
+			}  
+        Connection().Ldd().ReadUntilShort(iStatus, EndpointNumber(), iReceiveData);
+        SetActive();
+        if(needCommit != NULL)
+        	{
+        	TPtr8 tmp(NULL, 0, 0);
+        	needCommit->CommitChunkL(tmp);
+        	}
+        __FLOG(_L8("Request issued"));
+        }
+        
+    __FLOG_VA((_L8("CMTPUsbEpBase state on exit = 0x%08X"), iState));
+    __FLOG(_L8("CMTPUsbEpBase::ResumeReceiveDataStreamL - Exit"));
+    }
+    
+/**
+Implements the send data streaming algorithm. This algorithm regulates the 
+sequence of data chunks making up the send data stream to ensure that data is
+passed to the USB device interface in units of wMaxPacketSize integral length. 
+The algorithm attempts to avoid re-buffering unless absolutely necessary, as 
+follows:
+    1.  If the data chunk size is greater than or equal to the endpoint's 
+        wMaxPacketSize, then the maximum wMaxPacketSize integral data portion 
+        is sent directly. Any residual data is buffered in a wMaxPacketSize 
+        packet buffer.
+    2.  If the data chunk size is less than the endpoint's wMaxPacketSize, then
+        the data is buffered in the packet buffer. As soon as the packet buffer 
+        is filled it is sent.
+@leave One of the system wide error codes, if a processing failure occurs.
+*/
+void CMTPUsbEpBase::ProcessSendDataStreamL()
+    {
+    __FLOG(_L8("CMTPUsbEpBase::ProcessSendDataStreamL - Entry"));
+    __FLOG_VA((_L8("CMTPUsbEpBase state on entry = 0x%08X"), iState));
+    
+    // Clear the send data stream data pointer.
+    iSendData.Set(KNullDesC8);
+    
+    TUint chunkAvailableLen(iSendChunkData.Length());
+    if (!chunkAvailableLen)
+        {    
+        // Fetch the next read data chunk. 
+        switch (iState)
+            {
+        case ESendInitialising:
+            __FLOG(_L8("Fetching first read data chunk"));
+            iChunkStatus = iSendDataSource->FirstReadChunk(iSendChunkData);
+            iPacketBuffer.Zero();
+            break;
+            
+        case ESendInProgress:
+            __FLOG(_L8("Fetching next read data chunk"));
+            iChunkStatus = iSendDataSource->NextReadChunk(iSendChunkData);
+            break;
+            
+        case ESendCompleting:
+            break;
+            
+        case EIdle:
+        default:
+            __FLOG(_L8("Invalid send data stream state"));
+            Panic(EMTPUsbBadState);
+            break;
+            }
+        
+        // Fetch the new chunk data size available.
+        chunkAvailableLen = iSendChunkData.Length();
+        
+        // Update data stream state.
+        switch (iChunkStatus)
+            {
+        case KErrNone:
+            SetStreamState(ESendInProgress);
+            break;
+            
+        case KMTPChunkSequenceCompletion:
+            if (iState == ESendCompleting)
+                {
+                SetStreamState(ESendComplete);
+                }
+            else
+                {
+                SetStreamState(ESendCompleting);
+                }
+            break;
+            
+        default:
+            User::Leave(iChunkStatus);
+            break;
+            }          
+        }
+        
+    __FLOG_VA((_L8("Chunk status = %d"), iChunkStatus));
+    
+    // Process the buffered residual and/or available chunk data.
+    TUint bufferedLen(iPacketBuffer.Length());
+    TUint chunkIntegralLen((chunkAvailableLen / iPacketSizeMax) * iPacketSizeMax);
+    TUint chunkResidualLen(chunkAvailableLen % iPacketSizeMax);
+    TBool zlp(EFalse);
+    __FLOG_VA((_L8("Buffered residual data = %u bytes"), bufferedLen));
+    __FLOG_VA((_L8("Chunk data available = %u bytes"), chunkAvailableLen));
+    __FLOG_VA((_L8("Chunk data packet integral portion = %u bytes"), chunkIntegralLen));
+    __FLOG_VA((_L8("Chunk data packet residual portion = %u bytes"), chunkResidualLen));
+    
+    if (bufferedLen)
+        {
+        // Data is buffered in the packet buffer. Fill the available packet buffer space.
+        if (chunkAvailableLen)
+            {
+            // Fill the packet buffer.
+            TUint consumedLen(0);
+            TUint unconsumedLen(0);
+            TUint capacity(iPacketBuffer.MaxLength() - iPacketBuffer.Length());
+            if (chunkAvailableLen > capacity)
+                {
+                consumedLen     = capacity;
+                unconsumedLen   = (chunkAvailableLen - consumedLen);              
+                }
+            else
+                {
+                consumedLen = chunkAvailableLen;
+                }
+            __FLOG_VA((_L8("Buffering %u bytes"), consumedLen));
+            iPacketBuffer.Append(iSendChunkData.Left(consumedLen));
+            
+            // Update the available chunk data to reflect only the unconsumed portion.
+            __FLOG_VA((_L8("Residual chunk data = %u bytes"), unconsumedLen));
+            if (unconsumedLen)
+                {
+                iSendChunkData.Set(iSendChunkData.Right(unconsumedLen));
+                }
+            else
+                {
+                iSendChunkData.Set(NULL, 0);                    
+                }
+            }
+        
+        // Send the packet buffer when full.
+        if ((iState == ESendCompleting) || (iPacketBuffer.Size() == iPacketBuffer.MaxSize()))
+            {
+            iSendData.Set(iPacketBuffer);
+            iPacketBuffer.Zero();
+            }
+        
+        // Set the end of stream flag.
+        zlp = ((iState == ESendCompleting) && (iSendChunkData.Length() == 0));
+        }
+    else if (iState == ESendInProgress)
+        {
+        // Send the chunk data packet integral portion.
+        if (chunkIntegralLen)
+            {
+            iSendData.Set(iSendChunkData.Left(chunkIntegralLen));   
+            }
+    
+        // Buffer the chunk data packet residual portion.
+        if (chunkResidualLen)
+            {
+            __FLOG_VA((_L8("Buffering %u bytes"), chunkResidualLen));
+            iPacketBuffer.Append(iSendChunkData.Right(chunkResidualLen));  
+            }
+            
+        // All data has been consumed and/or buffered.
+        iSendChunkData.Set(NULL, 0);
+        }
+    else if (iState == ESendCompleting)
+        {
+        // Send all available chunk data.
+        iSendData.Set(iSendChunkData);
+        zlp = ETrue;
+            
+        // All data has been consumed.
+        iSendChunkData.Set(NULL, 0);
+        }
+
+    // Send the available data or reschedule to process the next chunk.
+    TUint sendBytes(iSendData.Length());
+    if ( sendBytes||zlp )
+        {
+        __FLOG_VA((_L8("Issuing Write request on endpoint %d, Zlp = %d"), EndpointNumber(), zlp));
+        __FLOG_VA((_L8("Send data length = %d bytes"), iSendData.Length()));
+        Connection().Ldd().Write(iStatus, EndpointNumber(), iSendData, sendBytes, zlp);
+        SetActive(); 
+        __FLOG(_L8("Request issued"));
+        }
+    else if (iState != ESendComplete)
+        {    
+        iStatus = KRequestPending;
+        TRequestStatus* status = &iStatus;
+        SetActive();
+        User::RequestComplete(status, KErrNone);
+        }
+
+    __FLOG_VA((_L8("CMTPUsbEpBase state on exit = 0x%08X"), iState));
+    __FLOG(_L8("CMTPUsbEpBase::ProcessSendDataStreamL - Exit"));   
+    }
+
+/**
+Sets the data stream state variable.
+@param aState The new data stream state.
+*/
+void CMTPUsbEpBase::SetStreamState(TInt aState)
+    {
+    __FLOG(_L8("SetStreamState - Entry"));
+    iState = aState;
+    __FLOG_VA((_L8("Stream state set to 0x%08X"), iState));
+    __FLOG(_L8("SetStreamState - Exit"));
+    }
+
+// Fix so that cancelling works.
+/*
+ * Flush USB driver received data
+ * 
+ */
+const TInt KFlushBufferMaxLen = 50*1024; // 50K bytes
+#define INTERVAL_FOR_READ_TRASH_DATA   (1000*50)  // 50 Miliseconds
+#define INTERVAL_FOR_FLUSH_TRASH_DATA  (9*INTERVAL_FOR_READ_TRASH_DATA)  // 450 Miliseconds
+// if there is no data read in flushRxData, wait for 1.5 second at most in case forever waiting
+#define INTERVAL_FOR_FLUSH_TRASH_DATA_IF_NO_DATA_READ  (30*INTERVAL_FOR_READ_TRASH_DATA) //1.5 SECOND 
+
+void CMTPUsbEpBase::FlushRxDataL()
+    {
+    				  
+    // create the read buff
+    RBuf8 readBuf;
+    readBuf.CreateL(KFlushBufferMaxLen);
+		      
+    TUint32 uRestTimeToWait = INTERVAL_FOR_FLUSH_TRASH_DATA_IF_NO_DATA_READ;
+ 			      
+    do{
+ 			    	
+      // get the data size in the receive buffer ready to read
+      TInt nbytes = 0;
+      TInt err = Connection().Ldd().QueryReceiveBuffer(EndpointNumber(), nbytes);
+#ifdef _DEBUG
+      RDebug::Print(_L("FlushRxDataL()--1---err is %d , nbytes is %d"), err, nbytes);	  
+#endif
+ 					  
+      // has data, read it
+      if( (err == KErrNone) && (nbytes > 0) )
+         {
+   
+         // synchronously read the data
+         TRequestStatus status;
+         Connection().Ldd().ReadOneOrMore(status, EndpointNumber(), readBuf);
+         User::WaitForRequest(status);
+	 		 
+         if(status.Int() != KErrNone)  break;
+         			               
+         // whenever some data read, reset the rest wait time .
+         uRestTimeToWait = INTERVAL_FOR_FLUSH_TRASH_DATA;
+ 			               
+#ifdef _DEBUG 			               
+         RDebug::Print(_L("FlushRxDataL()---Reset the rest wait time"));	  
+#endif             
+         }
+       else 
+         {	
+         // wait for the data from the usb channel.
+         User::After(INTERVAL_FOR_READ_TRASH_DATA);
+         // reduce the rest time to wait 
+         uRestTimeToWait -=  INTERVAL_FOR_READ_TRASH_DATA ;
+         }	
+ 	  
+#ifdef _DEBUG 	  
+       RDebug::Print(_L("FlushRxDataL()---uRestTimeToWait is %d"), uRestTimeToWait);	  
+#endif
+ 			    	
+    }while( uRestTimeToWait > 0);
+			    	
+    readBuf.Close();
+ 
+}