usbmgmt/usbmgr/device/classdrivers/ncm/classimplementation/ncmpktdrv/pktdrv/src/ncmdatasender.cpp
changeset 28 f1fd07aa74c9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/device/classdrivers/ncm/classimplementation/ncmpktdrv/pktdrv/src/ncmdatasender.cpp	Wed Jul 07 14:16:40 2010 +0800
@@ -0,0 +1,439 @@
+/*
+* Copyright (c) 2010 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 <e32base.h>
+
+#ifndef __OVER_DUMMYUSBSCLDD__
+#include <d32usbc.h>
+#else
+#include <dummyusbsclddapi.h>
+#endif
+
+#include "ncmdatasender.h"
+#include "ncmntb16builder.h"
+#include "ncmdatainterface.h"
+#include "ncmbuffermanager.h"
+#include "ncmntbbuildsimplepolicy.h"
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "ncmdatasenderTraces.h"
+#endif
+
+
+//
+//write buffer alignment value should get from share chunk LDD, current LDD has no API for this
+//use a pagesize here instead
+//
+const TInt KAlignSize = 1024;
+
+
+// ======== MEMBER FUNCTIONS ========
+//
+
+CNcmDataSender::CNcmDataSender(RDevUsbcScClient& aPort, CNcmDataInterface& aParent) : CActive(EPriorityStandard),
+                                            iPort(aPort),
+                                            iParent(aParent)
+    {
+    CActiveScheduler::Add(this);
+    }
+
+CNcmDataSender* CNcmDataSender::NewL(RDevUsbcScClient& aPort, CNcmDataInterface& aParent)
+    {
+    OstTraceFunctionEntry0( CNCMDATASENDER_NEWL_ENTRY );
+    CNcmDataSender *self = new (ELeave) CNcmDataSender(aPort, aParent);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    OstTraceFunctionExit0( CNCMDATASENDER_NEWL_EXIT );
+    return self;
+    }
+
+void CNcmDataSender::ConstructL()
+    {
+
+    iNtbBuilder = CNcmNtb16Builder::NewL(*this);
+    iBufferManager = CNcmBufferManager::NewL();
+    iBufferManager->SetAlignSize(KAlignSize);
+    iBuildPolicy = CNcmNtbBuildSimplePolicy::NewL(*iNtbBuilder);
+    iBuildPolicy->NtbBuilder().SetBuildPolicy(*iBuildPolicy);
+    iStarted = EFalse;
+    iStopSending = EFalse;
+    iIsSending = EFalse;
+    }
+
+CNcmDataSender::~CNcmDataSender()
+    {
+    Cancel();
+    delete iNtbBuilder;
+    delete iBufferManager;
+    delete iBuildPolicy;
+    }
+
+//
+// Start the sender
+//
+void CNcmDataSender::Start()
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_START_ENTRY, this );
+    if (iStarted)
+        {
+        OstTrace0( TRACE_ERROR, CNCMDATASENDER_START, "Alrealy start, return directly." );
+        OstTraceFunctionExit1( CNCMDATASENDER_START_EXIT, this );
+        return;
+        }
+
+    if (iStopSending)
+        {
+        iParent.ResumeSending();
+        iStopSending = EFalse;
+        }
+
+    TInt ret = iPort.OpenEndpoint(iEpOut, EEndpoint1);
+    if (ret != KErrNone)
+        {
+        OstTrace1( TRACE_FATAL, CNCMDATASENDER_START1, "OpenEndpoint error %d", ret );
+        iParent.DataError(ret);
+        OstTraceFunctionExit1( CNCMDATASENDER_START_EXIT_DUP1, this );
+        return;
+        }
+
+    TAny* buf = NULL;
+    TUint size;
+    ret = iEpOut.GetInBufferRange(buf, size);
+    if (ret != KErrNone)
+        {
+        OstTrace1( TRACE_FATAL, CNCMDATASENDER_START2, "iEpOut.GetInBufferRange failed ret=%d", ret );
+        iParent.DataError(ret);
+        OstTraceFunctionExit1( CNCMDATASENDER_START_EXIT_DUP2, this );
+        return;
+        }
+    else if (size < NtbInMaxSize())
+        {
+        OstTrace0( TRACE_FATAL, CNCMDATASENDER_START3, "LDD buffer size is small than NTB size" );
+        iParent.DataError(KErrArgument);
+        OstTraceFunctionExit1( CNCMDATASENDER_START_EXIT_DUP3, this );
+        return;
+        }
+    OstTraceExt2( TRACE_NORMAL, CNCMDATASENDER_START4, "GetInBufferRange at 0x%x size %d", (TUint)buf, size);
+
+
+    iBufferManager->InitBufferArea(buf, size);
+    ret = iBufferManager->SetBufferCellSize(NtbInMaxSize());
+    if (ret != KErrNone)
+        {
+        OstTrace1( TRACE_FATAL, CNCMDATASENDER_START5, "iBufferManager->SetBufferCellSize failed ret=%d", ret );
+        iParent.DataError(KErrArgument);
+        OstTraceFunctionExit1( CNCMDATASENDER_START_EXIT_DUP4, this );
+        return;
+        }
+    iBuildPolicy->UpdateBufferSize(NtbInMaxSize());
+    iBuildPolicy->UpdateTotalBufferCount(iBufferManager->FreeBufferCount());
+    iStarted = ETrue;
+    OstTraceFunctionExit1( CNCMDATASENDER_START_EXIT_DUP5, this );
+    }
+
+
+void CNcmDataSender::RunL()
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_RUNL_ENTRY, this );
+    OstTrace1( TRACE_NORMAL, CNCMDATASENDER_RUNL, "CNcmDataSender::RunL:Status=%d", iStatus.Int());
+
+    if(iStatus.Int() != KErrNone)
+        {
+        if (KErrCancel == iStatus.Int() )
+            {
+            }
+        else
+            {
+            iParent.DataError(iStatus.Int());
+            }
+        OstTraceFunctionExit1( CNCMDATASENDER_RUNL_EXIT, this );
+        return;
+        }
+    SendNtbComplete();
+    OstTraceFunctionExit1( CNCMDATASENDER_RUNL_EXIT_DUP1, this );
+    }
+
+//
+//Start a New Ntb in Builder
+//
+
+TInt CNcmDataSender::StartNewNtb()
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_STARTNEWNTB_ENTRY, this );
+    TNcmBuffer ncmBuffer;
+    TInt ret = iBufferManager->GetBuffer(ncmBuffer);
+	if (ret == KErrNone || ret == KErrCongestion)
+        {
+        iNtbBuilder->StartNewNtb(ncmBuffer);
+        }
+    else
+        {
+        OstTrace1( TRACE_FATAL, CNCMDATASENDER_STARTNEWNTB, "iBufferManager->GetBuffer failed ret=%d", ret);
+        }
+    OstTraceFunctionExit1( CNCMDATASENDER_STARTNEWNTB_EXIT, this );
+    return ret;
+    }
+
+
+//add a Ethernet packet to current NTB
+//
+
+TInt CNcmDataSender::Send(RMBufChain& aPacket)
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_SEND_ENTRY, this );
+
+    if (!iStarted)
+        {
+        OstTrace0( TRACE_WARNING, CNCMDATASENDER_SEND1, "Sender is not started" );
+        iStopSending = ETrue;
+        OstTraceFunctionExit1( CNCMDATASENDER_SEND_EXIT, this );
+        return KErrNotReady;
+        }
+
+    TInt ret = KErrNone;
+    if (!iNtbBuilder->IsNtbStarted())
+        {
+        ret = StartNewNtb();
+        if (ret != KErrNone && ret != KErrCongestion)
+            {
+            OstTraceFunctionExit1( CNCMDATASENDER_SEND_EXIT_DUP1, this );
+            return ret;
+            }
+        }
+
+    TBool isCongestion = (ret == KErrCongestion)?ETrue:EFalse;
+
+    ret = iNtbBuilder->AppendPacket(aPacket);
+
+    if (ret == KErrBufferFull)
+        {
+    //current NTB is full and can't add new packet, start a new NTB and insert packet to it
+        ret = StartNewNtb();
+        if (ret == KErrNone)
+            {
+            ret = iNtbBuilder->AppendPacket(aPacket);
+            }
+        else if (ret == KErrCongestion)
+            {
+            isCongestion = ETrue;
+            ret = iNtbBuilder->AppendPacket(aPacket);
+            }
+        }
+
+    if (isCongestion && ret == KErrNone)
+        {
+        OstTrace0( TRACE_NORMAL, CNCMDATASENDER_SEND2, "CNcmDataSender::Send congestion" );
+        iStopSending = ETrue;
+        OstTraceFunctionExit1( CNCMDATASENDER_SEND_EXIT_DUP2, this );
+        return KErrCongestion;
+        }
+    OstTraceFunctionExit1( CNCMDATASENDER_SEND_EXIT_DUP3, this );
+    return ret;
+    }
+
+//
+//Cancel the outgoing request of sending
+//
+
+void CNcmDataSender::DoCancel()
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_DOCANCEL_ENTRY, this );
+    iPort.WriteCancel(iEpOut.BufferNumber());
+    OstTraceFunctionExit1( CNCMDATASENDER_DOCANCEL_EXIT, this );
+    }
+
+void CNcmDataSender::SendNtbPayload(TNcmBuffer& aBuf)
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_SENDNTBPAYLOAD_ENTRY, this );
+    OstTraceExt2( TRACE_NORMAL, CNCMDATASENDER_SENDNTBPAYLOAD, "SendNtbPayload:%08x, len=%d", (TUint)aBuf.iPtr, aBuf.iLen);
+
+    if (iIsSending)
+        {
+        OstTrace0( TRACE_NORMAL, CNCMDATASENDER_SENDNTBPAYLOAD1, "SendNtbPayload: there is NTB on sending, store the buffer" );
+        iTxArray.Append(aBuf);
+        OstTraceFunctionExit1( CNCMDATASENDER_SENDNTBPAYLOAD_EXIT, this );
+        return;
+        }
+
+    iSendingBuffer = aBuf;
+    iIsSending = ETrue;
+
+    iStatus = KRequestPending;
+    TInt ret;
+    //
+    //   compliant to NCM spec with Zlp case
+    //
+    if (aBuf.iLen == NtbInMaxSize())
+        {
+        OstTrace0( TRACE_NORMAL, CNCMDATASENDER_SENDNTBPAYLOAD2, "iEpOut.WriteBuffer without zlp" );
+        ret = iEpOut.WriteBuffer((TAny*)aBuf.iPtr, aBuf.iLen, EFalse, iStatus);
+        }
+    else
+        {
+        OstTrace0( TRACE_NORMAL, CNCMDATASENDER_SENDNTBPAYLOAD3, "iEpOut.WriteBuffer with zlp" );
+        ret = iEpOut.WriteBuffer((TAny*)aBuf.iPtr, aBuf.iLen, ETrue, iStatus);
+        }
+    if (ret == KErrNone && !IsActive())
+        {
+        SetActive();
+        }
+    else
+        {
+        OstTrace1( TRACE_FATAL, CNCMDATASENDER_SENDNTBPAYLOAD4, "iEpOut.WriteBuffer failed ret = %d", ret);
+        iParent.DataError(ret);
+        }
+    OstTraceFunctionExit1( CNCMDATASENDER_SENDNTBPAYLOAD_EXIT_DUP1, this );
+    return;
+    }
+
+//
+// called when a sender request is completed by LDD
+//
+
+void CNcmDataSender::SendNtbComplete()
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_SENDNTBCOMPLETE_ENTRY, this );
+
+    iIsSending = EFalse;
+    iBufferManager->FreeBuffer(iSendingBuffer);
+    iBuildPolicy->UpdateFreeBufferCount(iBufferManager->FreeBufferCount());
+
+    // when buffer manage has enough buffers, notify networking to stop flow control
+    if (!iBufferManager->IsCongestion() && iStopSending)
+        {
+        iStopSending = EFalse;
+        iParent.ResumeSending();
+        }
+    if (iTxArray.Count())
+        {
+        OstTrace0( TRACE_NORMAL, CNCMDATASENDER_SENDNTBCOMPLETE3, "send NTB in sending queue" );
+        SendNtbPayload(iTxArray[0]);
+        iTxArray.Remove(0);
+        }
+    OstTraceFunctionExit1( CNCMDATASENDER_SENDNTBCOMPLETE_EXIT, this );
+    }
+
+void CNcmDataSender::GetNtbParam(TNcmNtbInParam& aParam)
+    {
+    iNtbBuilder->GetNtbParam(aParam);
+    }
+
+TInt CNcmDataSender::SetNtbInMaxSize(TInt aSize, TBool aIsAltZero)
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_SETNTBINMAXSIZE_ENTRY, this );
+    OstTrace1( TRACE_NORMAL, CNCMDATASENDER_SETNTBINMAXSIZE, "SetNtbInMaxSize %d", aSize);
+
+    TInt ret = iNtbBuilder->SetNtbInMaxSize(aSize);
+    if (ret != KErrNone)
+        {
+        OstTrace1( TRACE_FATAL, CNCMDATASENDER_SETNTBINMAXSIZE1, "iNtbBuilder->SetNtbInMaxSize failed %d", ret);
+        OstTraceFunctionExit1( CNCMDATASENDER_SETNTBINMAXSIZE_EXIT, this );
+        return ret;
+        }
+
+//
+//if sender is not started, endpoint buffer is not setup, so does not call SetBufferCellSize
+//
+    if (!iStarted)
+        {
+        OstTraceFunctionExit1( CNCMDATASENDER_SETNTBINMAXSIZE_EXIT_DUP1, this );
+        return KErrNone;
+        }
+
+//    if not in alternate setting 0, there may be data in buffer, so doesn't reset buffers.
+    if (!aIsAltZero)
+        {
+        OstTraceFunctionExit1( CNCMDATASENDER_SETNTBINMAXSIZE_EXIT_DUP2, this );
+        return KErrNone;
+        }
+
+    OstTraceFunctionExit1( CNCMDATASENDER_SETNTBINMAXSIZE_EXIT_DUP4, this );
+    return KErrNone;
+    }
+
+
+void CNcmDataSender::Stop()
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_STOP_ENTRY, this );
+    Cancel();
+    iBuildPolicy->Cancel();
+    iNtbBuilder->Reset();
+    iTxArray.Reset();
+    iEpOut.Close();
+    iStopSending = EFalse;
+    iStarted = EFalse;
+    iIsSending = EFalse;
+    OstTraceFunctionExit1( CNCMDATASENDER_STOP_EXIT, this );
+    }
+
+// call this function to notify the buffer size of In endpoint buffer size of LDD and adjust the MaxInNtbSize supported
+// report to host
+
+TInt CNcmDataSender::SetInEpBufferSize(TUint aSize)
+    {
+    OstTraceFunctionEntry1( CNCMDATASENDER_SETINEPBUFFERSIZE_ENTRY, this );
+    TInt ret = KErrNone;
+    TUint size = aSize;
+
+	OstTrace1( TRACE_NORMAL, CNCMDATASENDER_SETINEPBUFFERSIZE, "SetInEpBufferSize aSize=%d", aSize);
+
+
+// the buffer may not aligned, so decrease max possible offset due to aligment
+    size -= KAlignSize-1;
+    TInt ntbSize = iNtbBuilder->NtbInMaxSize();
+    TInt cellSize = KAlignSize;
+    TInt minNtbInMaxSize = iNtbBuilder->MinNtbInMaxSize();
+    TInt count;
+    TBool find = EFalse;
+    while (ntbSize >= minNtbInMaxSize)
+        {
+        cellSize = (ntbSize+KAlignSize-1)&~(KAlignSize-1);
+        count = size / cellSize;
+        if (count < iBufferManager->RequiredBufferCount())
+            {
+            ntbSize /= 2;
+            continue;
+            }
+        find = ETrue;
+        break;
+        }
+
+    if (ntbSize == iNtbBuilder->NtbInMaxSize())
+        {
+        ret = KErrNone;
+        }
+    else if (find)
+        {
+        ret = iNtbBuilder->SetNtbInMaxSize(cellSize);
+        }
+    else
+        {
+        ret = KErrGeneral;
+        }
+    OstTraceFunctionExit1( CNCMDATASENDER_SETINEPBUFFERSIZE_EXIT, this );
+    return ret;
+    }
+