usbdrv/peripheral/ldd/perildd/src/usbdma.cpp
branchRCL_3
changeset 15 f92a4f87e424
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbdrv/peripheral/ldd/perildd/src/usbdma.cpp	Tue Aug 31 17:01:47 2010 +0300
@@ -0,0 +1,983 @@
+// Copyright (c) 2000-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:
+// e32\drivers\usbc\usbdma.cpp
+// LDD for USB Device driver stack:
+// Management of DMA-capable data buffers.
+// 
+//
+
+/**
+ @file usbdma.cpp
+ @internalTechnology
+*/
+
+#include <usb/usbc.h>
+
+
+#if defined(_DEBUG)
+static const char KUsbPanicLdd[] = "USB LDD";
+#endif
+
+
+TDmaBuf::TDmaBuf(TUsbcEndpointInfo* aEndpointInfo, TInt aBandwidthPriority)
+    : iBufBasePtr(NULL),
+      iCurrentDrainingBuffer(NULL),
+      iCurrentPacket(0),
+      iCurrentPacketIndexArray(NULL),
+      iCurrentPacketSizeArray(NULL)
+    {
+    iMaxPacketSize = aEndpointInfo->iSize;
+    iEndpointType = aEndpointInfo->iType;
+
+    switch (aEndpointInfo->iType)
+        {
+    case UsbShai::KUsbEpTypeControl:
+        iBufSz = KUsbcDmaBufSzControl;
+        iNumberofBuffers = KUsbcDmaBufNumControl;
+        break;
+    case UsbShai::KUsbEpTypeIsochronous:
+        iBufSz = KUsbcDmaBufSzIsochronous;
+        iNumberofBuffers = KUsbcDmaBufNumIsochronous;
+        break;
+    case UsbShai::KUsbEpTypeBulk:
+        {
+        if (aEndpointInfo->iDir == UsbShai::KUsbEpDirOut)
+            {
+            const TInt priorityOUT = aBandwidthPriority & 0x0f;
+            iBufSz = KUsbcDmaBufSizesBulkOUT[priorityOUT];
+            }
+        else
+            {
+            const TInt priorityIN = (aBandwidthPriority >> 4) & 0x0f;
+            iBufSz = KUsbcDmaBufSizesBulkIN[priorityIN];
+            }
+        iNumberofBuffers = KUsbcDmaBufNumBulk;
+        }
+        break;
+    case UsbShai::KUsbEpTypeInterrupt:
+        iBufSz = KUsbcDmaBufSzInterrupt;
+        iNumberofBuffers = KUsbcDmaBufNumInterrupt;
+        break;
+    default:
+        iBufSz = 0;
+        iNumberofBuffers = 0;
+        }
+
+    if (aEndpointInfo->iDir == UsbShai::KUsbEpDirIn)
+        {
+        iNumberofBuffers = 1;                                // IN endpoints only have 1 buffer
+        }
+
+    for (TInt i = 0; i < KUsbcDmaBufNumMax; i++)
+        {
+        // Buffer logical addresses (pointers)
+        iBuffers[i] = NULL;
+        // Buffer physical addresses
+        iBufferPhys[i] = 0;
+        // Packet indexes base array
+        iPacketIndex[i] = NULL;
+        // Packet sizes base array
+        iPacketSize[i] = NULL;
+        }
+    }
+
+
+TInt TDmaBuf::Construct(TUsbcEndpointInfo* aEndpointInfo)
+    {
+    if (aEndpointInfo->iDir != UsbShai::KUsbEpDirIn)
+        {
+        // IN endpoints don't need a packet array
+
+        // At most 2 packets (clump of max packet size packets) + possible zlp
+        TUsbcPacketArray* bufPtr = iPacketInfoStorage;
+        // this divides up the packet indexing & packet size array over the number of buffers
+        __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() array base=0x%08x", bufPtr));
+        for (TInt i = 0; i < iNumberofBuffers; i++)
+            {
+            iPacketIndex[i] = bufPtr;
+            bufPtr += KUsbcDmaBufMaxPkts;
+            iPacketSize[i] = bufPtr;
+            bufPtr += KUsbcDmaBufMaxPkts;
+            __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() packetIndex[%d]=0x%08x packetSize[%d]=0x%08x",
+                                            i, iPacketIndex[i], i, iPacketSize[i]));
+            }
+        }
+    else
+        {
+        __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() IN endpoint"));
+        }
+    Flush();
+    return KErrNone;
+    }
+
+
+TDmaBuf::~TDmaBuf()
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::~TDmaBuf()"));
+    }
+
+TInt TDmaBuf::BufferTotalSize() const
+    {
+    return iBufSz * iNumberofBuffers;
+    }
+
+TInt TDmaBuf::BufferSize() const
+    {
+    return iBufSz;
+    }
+
+TInt TDmaBuf::SetBufferAddr(TInt aBufInd, TUint8* aBufAddr)
+    {
+    __ASSERT_DEBUG((aBufInd < iNumberofBuffers),
+                       Kern::Fault(KUsbPanicLdd, __LINE__));
+    iDrainable[aBufInd] = iCanBeFreed[aBufInd] = EFalse;
+    iBuffers[aBufInd] = aBufAddr;
+    iBufferPhys[aBufInd] = Epoc::LinearToPhysical((TLinAddr)aBufAddr);
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::SetBufferAddr() iBuffers[%d]=0x%08x", aBufInd, iBuffers[aBufInd]));
+    return KErrNone;
+    }
+
+TInt TDmaBuf::BufferNumber() const
+    {
+    return iNumberofBuffers;
+    }
+
+void TDmaBuf::SetMaxPacketSize(TInt aSize)
+    {
+    iMaxPacketSize = aSize;
+    }
+
+
+void TDmaBuf::Flush()
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Flush %x", this));
+    iRxActive = EFalse;
+    iTxActive = EFalse;
+    iExtractOffset = 0;
+    iTotalRxBytesAvail = 0;
+    iTotalRxPacketsAvail = 0;
+    iCurrentDrainingBufferIndex = KUsbcInvalidBufferIndex;
+    iCurrentFillingBufferIndex = 0;
+    iDrainQueueIndex = KUsbcInvalidDrainQueueIndex;
+    for (TInt i = 0; i < KUsbcDmaBufNumMax; i++)
+        {
+        iDrainable[i] = EFalse;
+        iCanBeFreed[i] = EFalse;
+        iNumberofBytesRx[i] = 0;
+        iNumberofPacketsRx[i] = 0;
+        iError[i] = KErrGeneral;
+        iDrainQueue[i] = KUsbcInvalidBufferIndex;
+#if defined(USBC_LDD_BUFFER_TRACE)
+        iFillingOrderArray[i] = 0;
+        iNumberofBytesRxRemain[i] = 0;
+        iNumberofPacketsRxRemain[i] = 0;
+#endif
+        }
+    // Drain queue is 1 oversized
+    iDrainQueue[KUsbcDmaBufNumMax] = KUsbcInvalidBufferIndex;
+
+#if defined(USBC_LDD_BUFFER_TRACE)
+    iFillingOrder = 0;
+    iDrainingOrder = 0;
+#endif
+    }
+
+
+void TDmaBuf::RxSetActive()
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxSetActive %x", this));
+    iRxActive = ETrue;
+    }
+
+
+void TDmaBuf::RxSetInActive()
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxSetInActive %x", this));
+    iRxActive = EFalse;
+    }
+
+
+TBool TDmaBuf::RxIsActive()
+    {
+    return iRxActive;
+    }
+
+
+void TDmaBuf::TxSetActive()
+    {
+    iTxActive = ETrue;
+    }
+
+
+void TDmaBuf::TxSetInActive()
+    {
+    iTxActive = EFalse;
+    }
+
+
+TBool TDmaBuf::TxIsActive()
+    {
+    return iTxActive;
+    }
+
+
+/**************************** Rx DMA Buffer Access *************************/
+
+void TDmaBuf::ModifyTotalRxBytesAvail(TInt aVal)
+    {
+    iTotalRxBytesAvail += aVal;
+    }
+
+
+void TDmaBuf::ModifyTotalRxPacketsAvail(TInt aVal)
+    {
+    iTotalRxPacketsAvail += aVal;
+    }
+
+
+TBool TDmaBuf::AdvancePacket()
+    {
+    ModifyTotalRxPacketsAvail(-1);
+    TBool r = ETrue;
+    __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0),
+                       Kern::Fault(KUsbPanicLdd, __LINE__));
+    if (++iCurrentPacket >= iNumberofPacketsRx[iCurrentDrainingBufferIndex])
+        {
+        r = NextDrainableBuffer();
+        }
+    iExtractOffset = 0;
+    __ASSERT_DEBUG((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) ||
+                   (iCurrentPacket < KUsbcDmaBufMaxPkts),
+                   Kern::Fault(KUsbPanicLdd, __LINE__));
+    return r;
+    }
+
+
+TInt TDmaBuf::PeekNextPacketSize()
+    {
+    TUint pkt = iCurrentPacket;
+    TInt index = iCurrentDrainingBufferIndex;
+    TInt size = -1;
+    if (pkt >= iNumberofPacketsRx[index])
+        {
+        index = PeekNextDrainableBuffer();
+        pkt = 0;
+        }
+
+    if ((index != KUsbcInvalidBufferIndex) && iNumberofPacketsRx[index])
+        {
+        const TUsbcPacketArray* sizeArray = iPacketSize[index];
+        size = (TInt)sizeArray[pkt];
+        }
+
+    __ASSERT_DEBUG((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) ||
+                   (iCurrentPacket < KUsbcDmaBufMaxPkts),
+                   Kern::Fault(KUsbPanicLdd, __LINE__));
+    return size;
+    }
+
+
+inline TInt TDmaBuf::GetCurrentError()
+    {
+    // USB bus errors are v.rare. To avoid having an error code attached to every packet since
+    // almost every errorcode will be KErrNone, we have a single error code per buffer
+    // If the error code is != KErrNone then it refers to the LAST packet in the buffer
+    TInt errorCode = KErrNone;
+    //Check the index, it's not equal to negative (-1) value defined in 
+    //KUsbcInvalidBufferIndex.
+    __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0),
+                       Kern::Fault(KUsbPanicLdd, __LINE__));
+    
+    if (iError[iCurrentDrainingBufferIndex] != KErrNone)
+        {
+        // See if we are at the last packet
+        if ((iCurrentPacket + 1) == iNumberofPacketsRx[iCurrentDrainingBufferIndex])
+            {
+            errorCode = iError[iCurrentDrainingBufferIndex];
+            }
+        }
+    return errorCode;
+    }
+
+
+// used to decide whether a client read can complete straight away
+TBool TDmaBuf::IsReaderEmpty()
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::IsReaderEmpty iTotalRxPacketsAvail=%d",
+                                    iTotalRxPacketsAvail));
+    return (iTotalRxPacketsAvail == 0);
+    }
+
+
+void TDmaBuf::ReadXferComplete(TInt aNoBytesRecv, TInt aNoPacketsRecv, TInt aErrorCode)
+    {
+    // Adjust pending packet
+    if ((aNoBytesRecv == 0) && (aErrorCode != KErrNone))
+        {
+        // Make the buffer available for reuse
+        iDrainable[iCurrentFillingBufferIndex] = EFalse;
+        return;
+        }
+
+    ModifyTotalRxBytesAvail(aNoBytesRecv);
+    ModifyTotalRxPacketsAvail(aNoPacketsRecv);
+    iNumberofBytesRx[iCurrentFillingBufferIndex] = aNoBytesRecv;
+    iNumberofPacketsRx[iCurrentFillingBufferIndex] = aNoPacketsRecv;
+
+#if defined(USBC_LDD_BUFFER_TRACE)
+    iNumberofBytesRxRemain[iCurrentFillingBufferIndex] = aNoBytesRecv;
+    iNumberofPacketsRxRemain[iCurrentFillingBufferIndex] = aNoPacketsRecv;
+#endif
+
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::ReadXferComplete 2 # of bytes=%d # of packets=%d",
+                                    iTotalRxBytesAvail, iTotalRxPacketsAvail));
+    iDrainable[iCurrentFillingBufferIndex] = ETrue;
+    iError[iCurrentFillingBufferIndex] = aErrorCode;
+    AddToDrainQueue(iCurrentFillingBufferIndex);
+    if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex)
+        {
+        NextDrainableBuffer();
+        }
+    }
+
+
+TInt TDmaBuf::RxGetNextXfer(TUint8*& aBufferAddr, TUsbcPacketArray*& aIndexArray,
+                            TUsbcPacketArray*& aSizeArray, TInt& aLength, TPhysAddr& aBufferPhys)
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer 1"));
+    if (RxIsActive())
+        {
+        __KTRACE_OPT(KUSB, Kern::Printf(" ---> RxIsActive, returning"));
+        return KErrInUse;
+        }
+
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer Current buffer=%d",
+                                    iCurrentFillingBufferIndex));
+    if (iDrainable[iCurrentFillingBufferIndex])
+        {
+        // If the controller refused the last read request, then the current buffer will still be marked
+        // as !Drainable, because the controller never completed the read to the ldd. and therefore the buffer
+        // can be reused.
+        if (!NextFillableBuffer())
+            {
+            return KErrNoMemory;
+            }
+        }
+
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer New buffer=%d",
+                                    iCurrentFillingBufferIndex));
+    aBufferAddr = iBuffers[iCurrentFillingBufferIndex];
+    aBufferPhys = iBufferPhys[iCurrentFillingBufferIndex];
+    aIndexArray = iPacketIndex[iCurrentFillingBufferIndex];
+    aSizeArray = iPacketSize[iCurrentFillingBufferIndex];
+    aLength = iBufSz;
+
+#if defined(USBC_LDD_BUFFER_TRACE)
+    iFillingOrderArray[iCurrentFillingBufferIndex] = ++iFillingOrder;
+#endif
+
+    return KErrNone;
+    }
+
+
+TInt TDmaBuf::RxCopyPacketToClient(DThread* aThread, TClientBuffer *aTcb, TInt aLength)
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 1"));
+
+#if defined(USBC_LDD_BUFFER_TRACE)
+    const TInt numPkts = NoRxPackets();
+    const TInt numPktsAlt = NoRxPacketsAlt();
+    const TInt numBytes = RxBytesAvailable();
+    const TInt numBytesAlt = NoRxBytesAlt();
+
+    if (numPkts != numPktsAlt)
+        {
+        Kern::Printf(
+            "TDmaBuf::RxCopyPacketToClient: Error: #pkts mismatch global=%d actual=%d",
+            numPkts, numPktsAlt);
+        }
+    if (numBytes != numBytesAlt)
+        {
+        Kern::Printf(
+            "TDmaBuf::RxCopyPacketToClient: Error: #bytes mismatch global=%d actual=%d",
+            numBytes, numBytesAlt);
+        }
+    if ((numPkts == 0) && (numBytes !=0))
+        {
+        Kern::Printf(
+            "TDmaBuf::RxCopyPacketToClient: Error: global bytes & pkts mismatch pkts=%d bytes=%d",
+            numPkts, numBytes);
+        }
+    if ((numPktsAlt == 0) && (numBytesAlt !=0))
+        {
+        Kern::Printf(
+            "TDmaBuf::RxCopyPacketToClient: Error: actual bytes & pkts mismatch pkts=%d bytes=%d",
+            numPktsAlt, numBytesAlt);
+        }
+#endif
+
+    if (!NoRxPackets())
+        return KErrNotFound;
+
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 2"));
+    // the next condition should be true because we have some packets available
+    // coverity[var_tested_neg]
+    if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex)
+        {
+        // Marked as Coverity "Intentional" as the member variable
+        // iCurrentDrainingBufferIndex is attentionaly negative, from previous 
+        // initialization to KUsbcInvalidBufferIndex (which equals -1).
+        if (!NextDrainableBuffer())
+            return KErrNotFound;
+        }
+
+    __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0 ),
+                           Kern::Fault(KUsbPanicLdd, __LINE__));
+    
+    if (!iDrainable[iCurrentDrainingBufferIndex])
+        return KErrNotFound;
+
+    // Calculate copy-from address & adjust for the fact that
+    // some data may have already been read from the packet
+    TUint8* logicalSrc = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset;
+    TInt packetSz = iCurrentPacketSizeArray[iCurrentPacket];
+    TInt thisPacketSz = packetSz - iExtractOffset;
+    TInt errorCode;
+    // try and sort out what a "packet" might mean.
+    // in a multi-packet dma environment, we might see super-packets
+    // i.e. we might just see one packet, maybe 4K or so long, made of lots of small packets
+    // Since we don't know where the packet boundaries will be, we have to assume that
+    // any 'packet' larger than the max packet size of the ep is, in fact, a conglomeration
+    // of smaller packets. However, for the purposes of the packet count, this is still regarded
+    // as a single packet and the packet count only decremented when it is consumed.
+    // As before, if the user fails to read an entire packet out then the next packet is moved onto anyway
+    // To be safe the user must always supply a buffer of at least max packet size bytes.
+    if (thisPacketSz > iMaxPacketSize)
+        {
+        // Multiple packets left in buffer
+        // calculate number of bytes to end of packet
+        if (iEndpointType == UsbShai::KUsbEpTypeBulk)
+            {
+            thisPacketSz = iMaxPacketSize - (iExtractOffset & (iMaxPacketSize - 1));
+            }
+        else
+            {
+            thisPacketSz = iMaxPacketSize - (iExtractOffset % iMaxPacketSize);
+            }
+        errorCode = KErrNone;
+        }
+    else
+        {
+        errorCode = GetCurrentError();                        // single packet left
+        }
+
+    iExtractOffset += thisPacketSz;            // iExtractOffset is now at the end of the real or notional packet
+
+    ModifyTotalRxBytesAvail(-thisPacketSz);
+#if defined(USBC_LDD_BUFFER_TRACE)
+    iNumberofBytesRxRemain[iCurrentDrainingBufferIndex] -= thisPacketSz;
+#endif
+    // this can only be untrue if the "packet" is a conglomeration of smaller packets:
+    if (iExtractOffset == packetSz)
+        {
+        // packet consumed, advance to next packet in buffer
+#if defined(USBC_LDD_BUFFER_TRACE)
+        iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1;
+#endif
+        AdvancePacket();
+        }
+
+    TPtrC8 des(logicalSrc, thisPacketSz);
+    TInt r=Kern::ThreadBufWrite(aThread, aTcb, des, 0, 0, aThread);
+    if (r == KErrNone)
+        {
+        r = errorCode;
+        }
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 3"));
+
+    FreeDrainedBuffers();
+
+    // Use this error code to complete client read request:
+    return r;
+    }
+
+
+TInt TDmaBuf::RxCopyDataToClient(DThread* aThread, TClientBuffer *aTcb, TInt aLength, TUint32& aDestOffset,
+                                 TBool aRUS, TBool& aCompleteNow)
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyDataToClient 1"));
+    aCompleteNow = ETrue;
+
+#if defined(USBC_LDD_BUFFER_TRACE)
+    const TInt numPkts = NoRxPackets();
+    const TInt numPktsAlt = NoRxPacketsAlt();
+    const TInt numBytes = RxBytesAvailable();
+    const TInt numBytesAlt = NoRxBytesAlt();
+
+    if (numPkts != numPktsAlt)
+        {
+        Kern::Printf(
+            "TDmaBuf::RxCopyDataToClient: Error: #pkts mismatch global=%d actual=%d",
+            numPkts, numPktsAlt);
+        }
+    if (numBytes != numBytesAlt)
+        {
+        Kern::Printf(
+            "TDmaBuf::RxCopyDataToClient: Error: #bytes mismatch global=%d actual=%d",
+            numBytes, numBytesAlt);
+        }
+    if ((numPkts == 0) && (numBytes != 0))
+        {
+        Kern::Printf(
+            "TDmaBuf::RxCopyDataToClient: Error: global bytes & pkts mismatch pkts=%d bytes=%d",
+            numPkts, numBytes);
+        }
+    if ((numPktsAlt == 0) && (numBytesAlt != 0))
+        {
+        Kern::Printf(
+            "TDmaBuf::RxCopyDataToClient: Error: actual bytes & pkts mismatch pkts=%d bytes=%d",
+            numPktsAlt, numBytesAlt);
+        }
+#endif
+
+    if (!NoRxPackets())
+        {
+        return KErrNotFound;
+        }
+
+    // coverity[var_tested_neg]
+    if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex)
+        {
+        // Marked as Coverity "Inentional" as the member variable
+        // iCurrentDrainingBufferIndex is attentionaly negative, from previous 
+        // initialization to KUsbcInvalidBufferIndex (which equals -1).
+
+        if (!NextDrainableBuffer())
+            {
+#if defined(USBC_LDD_BUFFER_TRACE)
+            Kern::Printf("TDmaBuf::RxCopyDataToClient: Error:  No buffer draining=%d, packets=%d",
+                         iCurrentDrainingBufferIndex, iTotalRxPacketsAvail);
+#endif
+            return KErrNotFound;
+            }
+        }
+#if defined(USBC_LDD_BUFFER_TRACE)
+
+    __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0 ),
+                               Kern::Fault(KUsbPanicLdd, __LINE__));
+        
+    if (iDrainingOrder != iFillingOrderArray[iCurrentDrainingBufferIndex])
+        {
+        Kern::Printf("!!! Out of Order Draining TDmaBuf::RxCopyDataToClient 10 draining=%d",
+                     iCurrentDrainingBufferIndex);
+        }
+#endif
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyDataToClient 2"));
+
+    TUint8* blockStartAddr = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset;
+    TUint8* lastEndAddr = blockStartAddr;                    // going to track the contiguity of the memory
+    TUint8* thisStartAddr = blockStartAddr;
+    TInt toDo = Min(aLength - (TInt)aDestOffset, iTotalRxBytesAvail);
+#if defined(USBC_LDD_BUFFER_TRACE)
+    TInt bufnum = iCurrentDrainingBufferIndex;
+#endif
+    TInt errorCode = KErrNone;
+    TBool isShortPacket = EFalse;
+    const TInt maxPacketSizeMask = iMaxPacketSize - 1;
+    do
+        {
+#if defined(USBC_LDD_BUFFER_TRACE)
+        if (bufnum != iCurrentDrainingBufferIndex)
+            {
+            bufnum = iCurrentDrainingBufferIndex;
+            if (iDrainingOrder != iFillingOrderArray[iCurrentDrainingBufferIndex])
+                {
+                Kern::Printf("!!! Out of Order Draining TDmaBuf::RxCopyDataToClient 20 draining=%d",
+                             iCurrentDrainingBufferIndex);
+                }
+            }
+#endif
+        if (errorCode == KErrNone)
+            {
+            errorCode = GetCurrentError();
+            }
+        thisStartAddr = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset;
+        const TInt thisPacketSize = iCurrentPacketSizeArray[iCurrentPacket];
+        const TInt size = thisPacketSize - iExtractOffset;
+        if (aRUS)
+            {
+            if (iEndpointType == UsbShai::KUsbEpTypeBulk)
+                {
+                isShortPacket = (size < iMaxPacketSize) || (size & maxPacketSizeMask);
+                }
+            else
+                {
+                // this 'if' block is arranged to avoid a division on packet sizes <= iMaxPacketSize
+                isShortPacket = (size < iMaxPacketSize) ||
+                    ((size > iMaxPacketSize) && (size % iMaxPacketSize));
+                }
+            }
+        TInt copySize = Min(size, toDo);
+        iExtractOffset += copySize;
+        toDo -= copySize;
+        if (thisStartAddr != lastEndAddr)
+            {
+            TInt bytesToCopy = lastEndAddr - blockStartAddr;
+            TInt r=CopyToUser(aThread, blockStartAddr, bytesToCopy, aTcb, aDestOffset);
+            if(r != KErrNone)
+                Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat);
+            blockStartAddr = thisStartAddr;
+            }
+
+        ModifyTotalRxBytesAvail(-copySize);
+#if defined(USBC_LDD_BUFFER_TRACE)
+        iNumberofBytesRxRemain[iCurrentDrainingBufferIndex] -= copySize;
+#endif
+        lastEndAddr = thisStartAddr + copySize;
+        if (iExtractOffset == thisPacketSize)
+            {
+            // More data to copy, so need to access new packet
+#if defined(USBC_LDD_BUFFER_TRACE)
+            iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1;
+#endif
+            if (!AdvancePacket())
+                {
+                break;                                        // no more packets left
+                }
+            }
+        } while (toDo > 0 && !isShortPacket);
+
+    if (thisStartAddr != lastEndAddr)
+        {
+        TInt bytesToCopy = lastEndAddr - blockStartAddr;
+        TInt r=CopyToUser(aThread, blockStartAddr, bytesToCopy, aTcb, aDestOffset);
+        if(r != KErrNone)
+            Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat);
+        }
+
+    // If we have transferred the requested amount of data it is still possible that
+    // the next packet is a zlp which needs to be bumped over
+
+    if (aRUS && (toDo == 0) && (iExtractOffset == 0) && (!isShortPacket) && (!IsReaderEmpty()) &&
+        (PeekNextPacketSize() == 0))
+        {
+        // swallow a zlp
+        isShortPacket = ETrue;
+#if defined(USBC_LDD_BUFFER_TRACE)
+        iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1;
+#endif
+        AdvancePacket();
+        }
+    aCompleteNow = isShortPacket || (((TInt)aDestOffset) == aLength) || (errorCode != KErrNone);
+
+    FreeDrainedBuffers();
+
+    // Use this error code to complete client read request
+    return errorCode;
+    }
+
+
+inline TInt TDmaBuf::CopyToUser(DThread* aThread, const TUint8* aSourceAddr,
+                                TInt aLength, TClientBuffer *aTcb, TUint32& aDestOffset)
+    {
+    TPtrC8 des(aSourceAddr, aLength);
+    TInt errorCode = Kern::ThreadBufWrite(aThread, aTcb, des, aDestOffset, KChunkShiftBy0, aThread);
+    if (errorCode == KErrNone)
+        {
+        aDestOffset += aLength;
+        }
+    return errorCode;
+    }
+
+
+inline TInt TDmaBuf::NoRxPackets() const
+    {
+    return iTotalRxPacketsAvail;
+    }
+
+
+inline void TDmaBuf::IncrementBufferIndex(TInt& aIndex)
+    {
+    if (++aIndex == iNumberofBuffers)
+        aIndex = 0;
+    }
+
+
+TBool TDmaBuf::NextDrainableBuffer()
+    {
+    TBool r = EFalse;
+    if (iCurrentDrainingBufferIndex != KUsbcInvalidBufferIndex)
+        {
+        iCanBeFreed[iCurrentDrainingBufferIndex] = ETrue;
+        iNumberofPacketsRx[iCurrentDrainingBufferIndex] = 0; // Current buffer is empty
+        iNumberofBytesRx[iCurrentDrainingBufferIndex] = 0;    // Current buffer is empty
+
+#if defined(USBC_LDD_BUFFER_TRACE)
+        TUint& bytesRemain = iNumberofBytesRxRemain[iCurrentDrainingBufferIndex];
+        TUint& pktsRemain = iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex];
+        if ((bytesRemain != 0) || (pktsRemain != 0))
+            {
+            Kern::Printf(
+                "TDmaBuf::NextDrainableBuffer: Error: data discarded buffer=%d pkts=%d bytes=%d",
+                iCurrentDrainingBufferIndex, pktsRemain, bytesRemain);
+            bytesRemain = 0;
+            pktsRemain = 0;
+            }
+#endif
+
+        iCurrentDrainingBufferIndex = KUsbcInvalidBufferIndex;
+        iCurrentPacket = KUsbcInvalidPacketIndex;
+        }
+
+    if (iDrainQueueIndex != KUsbcInvalidDrainQueueIndex)
+        {
+        r = ETrue;
+        const TInt index = iDrainQueue[0];
+        iDrainQueueIndex--;
+        for (TInt i = 0; i < iNumberofBuffers; i++)
+            {
+            iDrainQueue[i] = iDrainQueue[i+1];
+            }
+
+#if defined(USBC_LDD_BUFFER_TRACE)
+        if (index != KUsbcInvalidBufferIndex)
+            iDrainingOrder++;
+#endif
+
+        iCurrentDrainingBufferIndex = index;
+        iCurrentDrainingBuffer = iBuffers[index];
+        iCurrentPacketIndexArray = iPacketIndex[index];
+        iCurrentPacketSizeArray = iPacketSize[index];
+        iCurrentPacket = 0;
+        }
+    return r;
+    }
+
+
+TInt TDmaBuf::PeekNextDrainableBuffer()
+    {
+    TInt r = KUsbcInvalidBufferIndex;
+    if (iDrainQueueIndex != KUsbcInvalidDrainQueueIndex)
+        {
+        r = iDrainQueue[0];
+        }
+    return r;
+    }
+
+
+TBool TDmaBuf::NextFillableBuffer()
+    {
+    TBool r = EFalse;
+    TInt index = iCurrentFillingBufferIndex;
+    IncrementBufferIndex(index);
+    // the sequence will restart at 0 if a buffer can't be found this time
+    iCurrentFillingBufferIndex = 0;
+    for (TInt i = 0; i < iNumberofBuffers; i++)
+        {
+        if (!iDrainable[index])
+            {
+            iCurrentFillingBufferIndex = index;
+            r = ETrue;
+            break;
+            }
+        IncrementBufferIndex(index);
+        }
+    return r;
+    }
+
+
+void TDmaBuf::FreeDrainedBuffers()
+    {
+    for (TInt i = 0; i < iNumberofBuffers; i++)
+        {
+        if (iDrainable[i] && iCanBeFreed[i])
+            {
+            iDrainable[i] = iCanBeFreed[i] = EFalse;
+            }
+        }
+    }
+
+
+TBool TDmaBuf::ShortPacketExists()
+    {
+    // Actually, a short packet or residue data
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::ShortPacketExists 1"));
+    TInt index = iCurrentDrainingBufferIndex;
+    TUsbcPacketArray* pktSizeArray = iCurrentPacketSizeArray;
+
+    if (iMaxPacketSize > 0)
+        {
+        // No buffers available for draining
+        if ((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) ||
+            (iCurrentPacket == KUsbcInvalidPacketIndex))
+            return EFalse;
+
+        // Zlp waiting at tail
+        if ((iTotalRxBytesAvail == 0) && (NoRxPackets() == 1))
+            return ETrue;
+
+        if (iEndpointType == UsbShai::KUsbEpTypeBulk)
+            {
+            const TInt mask = iMaxPacketSize - 1;
+            if (iTotalRxBytesAvail & mask)
+                return ETrue;
+
+            // residue==0; this can be because
+            // zlps exist, or short packets combine to n * max_packet_size
+            // This means spadework
+            const TInt s = iCurrentPacketSizeArray[iCurrentPacket] - iExtractOffset;
+            if ((s == 0) || (s & mask))
+                {
+                return ETrue;
+                }
+
+            for (TInt i = 0; i < iNumberofBuffers; i++)
+                {
+                if (index == KUsbcInvalidBufferIndex)
+                    break;
+                if (iDrainable[index])
+                    {
+                    const TInt packetCount = iNumberofPacketsRx[index];
+                    const TInt lastPacketSize=pktSizeArray[packetCount - 1];
+                    if ((lastPacketSize < iMaxPacketSize) || (lastPacketSize & mask))
+                        {
+                        return ETrue;
+                        }
+                    }
+                index = iDrainQueue[i];
+                pktSizeArray = iPacketSize[index];
+                }
+            }
+        else
+            {
+            if (iTotalRxBytesAvail % iMaxPacketSize)
+                return ETrue;
+
+            // residue==0; this can be because
+            // zlps exist, or short packets combine to n * max_packet_size
+            // This means spadework
+            const TInt s = iCurrentPacketSizeArray[iCurrentPacket] - iExtractOffset;
+            if ((s == 0) || (s % iMaxPacketSize))
+                {
+                return ETrue;
+                }
+
+            for (TInt i = 0; i < iNumberofBuffers; i++)
+                {
+                if (index == KUsbcInvalidBufferIndex)
+                    break;
+                if (iDrainable[index])
+                    {
+                    const TInt packetCount = iNumberofPacketsRx[index];
+                    const TInt lastPacketSize = pktSizeArray[packetCount - 1];
+                    if ((lastPacketSize < iMaxPacketSize) || (lastPacketSize % iMaxPacketSize))
+                        {
+                        return ETrue;
+                        }
+                    }
+                index = iDrainQueue[i];
+                pktSizeArray = iPacketSize[index];
+                }
+            }
+        }
+
+    return EFalse;
+    }
+
+
+void TDmaBuf::AddToDrainQueue(TInt aBufferIndex)
+    {
+    if (iDrainQueue[iDrainQueueIndex + 1] != KUsbcInvalidBufferIndex)
+        {
+#if defined(USBC_LDD_BUFFER_TRACE)
+        Kern::Printf("TDmaBuf::AddToDrainQueue: Error: invalid iDrainQueue[x]");
+#endif
+        }
+    iDrainQueue[++iDrainQueueIndex] = aBufferIndex;
+    }
+
+
+#if defined(USBC_LDD_BUFFER_TRACE)
+TInt TDmaBuf::NoRxPacketsAlt() const
+    {
+    TInt pktCount = 0;
+    for(TInt i = 0; i < iNumberofBuffers; i++)
+        {
+        if (iDrainable[i])
+            {
+            pktCount += iNumberofPacketsRxRemain[i];
+            }
+        }
+    return pktCount;
+    }
+
+
+TInt TDmaBuf::NoRxBytesAlt() const
+    {
+    TInt byteCount = 0;
+    for(TInt i = 0; i < iNumberofBuffers; i++)
+        {
+        if (iDrainable[i])
+            {
+            byteCount += iNumberofBytesRxRemain[i];
+            }
+        }
+    return byteCount;
+    }
+#endif
+
+
+// We only store 1 transaction, no other buffering is done
+TInt TDmaBuf::TxStoreData(DThread* aThread, TClientBuffer *aTcb, TInt aTxLength, TUint32 aBufferOffset)
+    {
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::TxStoreData 1"));
+    if (!IsReaderEmpty())
+        return KErrInUse;
+
+    __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::TxStoreData 2"));
+    
+    TInt remainTxLength = aTxLength;
+    TUint32 bufferOffset = aBufferOffset;
+    // Store each buffer separately
+    for( TInt i=0;(i<iNumberofBuffers)&&(remainTxLength>0);i++)
+        {
+        TUint8* logicalDest = iBuffers[i];
+        TInt xferSz = Min(remainTxLength, iBufSz);
+        TPtr8 des(logicalDest, xferSz, xferSz);
+        TInt r = Kern::ThreadBufRead(aThread, aTcb, des, bufferOffset, KChunkShiftBy0);
+        if(r != KErrNone)
+            {
+            Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat);
+            return r;
+            }
+        remainTxLength -= iBufSz;
+        bufferOffset += iBufSz;
+        }
+
+    return KErrNone;
+    }
+
+
+TInt TDmaBuf::TxGetNextXfer(TUint8*& aBufferAddr, TInt& aTxLength, TPhysAddr& aBufferPhys)
+    {
+    if (iTxActive)
+        return KErrInUse;
+
+    aBufferAddr = iBuffers[0];                                // only 1 tx buffer
+    aBufferPhys = iBufferPhys[0];
+    aTxLength = BufferTotalSize();
+
+    return KErrNone;
+    }
+