Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// 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 <drivers/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 KUsbEpTypeControl:
iBufSz = KUsbcDmaBufSzControl;
iNumberofBuffers = KUsbcDmaBufNumControl;
break;
case KUsbEpTypeIsochronous:
iBufSz = KUsbcDmaBufSzIsochronous;
iNumberofBuffers = KUsbcDmaBufNumIsochronous;
break;
case KUsbEpTypeBulk:
{
if (aEndpointInfo->iDir == KUsbEpDirOut)
{
const TInt priorityOUT = aBandwidthPriority & 0x0f;
iBufSz = KUsbcDmaBufSizesBulkOUT[priorityOUT];
}
else
{
const TInt priorityIN = (aBandwidthPriority >> 4) & 0x0f;
iBufSz = KUsbcDmaBufSizesBulkIN[priorityIN];
}
iNumberofBuffers = KUsbcDmaBufNumBulk;
}
break;
case KUsbEpTypeInterrupt:
iBufSz = KUsbcDmaBufSzInterrupt;
iNumberofBuffers = KUsbcDmaBufNumInterrupt;
break;
default:
iBufSz = 0;
iNumberofBuffers = 0;
}
if (aEndpointInfo->iDir == 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 != 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 == 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 == 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 == 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;
}