First public contribution.
1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\drivers\usbc\usbdma.cpp
15 // LDD for USB Device driver stack:
16 // Management of DMA-capable data buffers.
25 #include <drivers/usbc.h>
29 static const char KUsbPanicLdd[] = "USB LDD";
33 TDmaBuf::TDmaBuf(TUsbcEndpointInfo* aEndpointInfo, TInt aBandwidthPriority)
35 iCurrentDrainingBuffer(NULL),
37 iCurrentPacketIndexArray(NULL),
38 iCurrentPacketSizeArray(NULL)
40 iMaxPacketSize = aEndpointInfo->iSize;
41 iEndpointType = aEndpointInfo->iType;
43 switch (aEndpointInfo->iType)
45 case KUsbEpTypeControl:
46 iBufSz = KUsbcDmaBufSzControl;
47 iNumberofBuffers = KUsbcDmaBufNumControl;
49 case KUsbEpTypeIsochronous:
50 iBufSz = KUsbcDmaBufSzIsochronous;
51 iNumberofBuffers = KUsbcDmaBufNumIsochronous;
55 if (aEndpointInfo->iDir == KUsbEpDirOut)
57 const TInt priorityOUT = aBandwidthPriority & 0x0f;
58 iBufSz = KUsbcDmaBufSizesBulkOUT[priorityOUT];
62 const TInt priorityIN = (aBandwidthPriority >> 4) & 0x0f;
63 iBufSz = KUsbcDmaBufSizesBulkIN[priorityIN];
65 iNumberofBuffers = KUsbcDmaBufNumBulk;
68 case KUsbEpTypeInterrupt:
69 iBufSz = KUsbcDmaBufSzInterrupt;
70 iNumberofBuffers = KUsbcDmaBufNumInterrupt;
77 if (aEndpointInfo->iDir == KUsbEpDirIn)
79 iNumberofBuffers = 1; // IN endpoints only have 1 buffer
82 for (TInt i = 0; i < KUsbcDmaBufNumMax; i++)
84 // Buffer logical addresses (pointers)
86 // Buffer physical addresses
88 // Packet indexes base array
89 iPacketIndex[i] = NULL;
90 // Packet sizes base array
91 iPacketSize[i] = NULL;
96 TInt TDmaBuf::Construct(TUsbcEndpointInfo* aEndpointInfo)
98 if (aEndpointInfo->iDir != KUsbEpDirIn)
100 // IN endpoints don't need a packet array
102 // At most 2 packets (clump of max packet size packets) + possible zlp
103 TUsbcPacketArray* bufPtr = iPacketInfoStorage;
104 // this divides up the packet indexing & packet size array over the number of buffers
105 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() array base=0x%08x", bufPtr));
106 for (TInt i = 0; i < iNumberofBuffers; i++)
108 iPacketIndex[i] = bufPtr;
109 bufPtr += KUsbcDmaBufMaxPkts;
110 iPacketSize[i] = bufPtr;
111 bufPtr += KUsbcDmaBufMaxPkts;
112 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() packetIndex[%d]=0x%08x packetSize[%d]=0x%08x",
113 i, iPacketIndex[i], i, iPacketSize[i]));
118 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() IN endpoint"));
127 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::~TDmaBuf()"));
130 TInt TDmaBuf::BufferTotalSize() const
132 return iBufSz * iNumberofBuffers;
135 TInt TDmaBuf::BufferSize() const
140 TInt TDmaBuf::SetBufferAddr(TInt aBufInd, TUint8* aBufAddr)
142 __ASSERT_DEBUG((aBufInd < iNumberofBuffers),
143 Kern::Fault(KUsbPanicLdd, __LINE__));
144 iDrainable[aBufInd] = iCanBeFreed[aBufInd] = EFalse;
145 iBuffers[aBufInd] = aBufAddr;
146 iBufferPhys[aBufInd] = Epoc::LinearToPhysical((TLinAddr)aBufAddr);
147 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::SetBufferAddr() iBuffers[%d]=0x%08x", aBufInd, iBuffers[aBufInd]));
151 TInt TDmaBuf::BufferNumber() const
153 return iNumberofBuffers;
156 void TDmaBuf::SetMaxPacketSize(TInt aSize)
158 iMaxPacketSize = aSize;
162 void TDmaBuf::Flush()
164 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Flush %x", this));
168 iTotalRxBytesAvail = 0;
169 iTotalRxPacketsAvail = 0;
170 iCurrentDrainingBufferIndex = KUsbcInvalidBufferIndex;
171 iCurrentFillingBufferIndex = 0;
172 iDrainQueueIndex = KUsbcInvalidDrainQueueIndex;
173 for (TInt i = 0; i < KUsbcDmaBufNumMax; i++)
175 iDrainable[i] = EFalse;
176 iCanBeFreed[i] = EFalse;
177 iNumberofBytesRx[i] = 0;
178 iNumberofPacketsRx[i] = 0;
179 iError[i] = KErrGeneral;
180 iDrainQueue[i] = KUsbcInvalidBufferIndex;
181 #if defined(USBC_LDD_BUFFER_TRACE)
182 iFillingOrderArray[i] = 0;
183 iNumberofBytesRxRemain[i] = 0;
184 iNumberofPacketsRxRemain[i] = 0;
187 // Drain queue is 1 oversized
188 iDrainQueue[KUsbcDmaBufNumMax] = KUsbcInvalidBufferIndex;
190 #if defined(USBC_LDD_BUFFER_TRACE)
197 void TDmaBuf::RxSetActive()
199 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxSetActive %x", this));
204 void TDmaBuf::RxSetInActive()
206 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxSetInActive %x", this));
211 TBool TDmaBuf::RxIsActive()
217 void TDmaBuf::TxSetActive()
223 void TDmaBuf::TxSetInActive()
229 TBool TDmaBuf::TxIsActive()
235 /**************************** Rx DMA Buffer Access *************************/
237 void TDmaBuf::ModifyTotalRxBytesAvail(TInt aVal)
239 iTotalRxBytesAvail += aVal;
243 void TDmaBuf::ModifyTotalRxPacketsAvail(TInt aVal)
245 iTotalRxPacketsAvail += aVal;
249 TBool TDmaBuf::AdvancePacket()
251 ModifyTotalRxPacketsAvail(-1);
253 __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0),
254 Kern::Fault(KUsbPanicLdd, __LINE__));
255 if (++iCurrentPacket >= iNumberofPacketsRx[iCurrentDrainingBufferIndex])
257 r = NextDrainableBuffer();
260 __ASSERT_DEBUG((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) ||
261 (iCurrentPacket < KUsbcDmaBufMaxPkts),
262 Kern::Fault(KUsbPanicLdd, __LINE__));
267 TInt TDmaBuf::PeekNextPacketSize()
269 TUint pkt = iCurrentPacket;
270 TInt index = iCurrentDrainingBufferIndex;
272 if (pkt >= iNumberofPacketsRx[index])
274 index = PeekNextDrainableBuffer();
278 if ((index != KUsbcInvalidBufferIndex) && iNumberofPacketsRx[index])
280 const TUsbcPacketArray* sizeArray = iPacketSize[index];
281 size = (TInt)sizeArray[pkt];
284 __ASSERT_DEBUG((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) ||
285 (iCurrentPacket < KUsbcDmaBufMaxPkts),
286 Kern::Fault(KUsbPanicLdd, __LINE__));
291 inline TInt TDmaBuf::GetCurrentError()
293 // USB bus errors are v.rare. To avoid having an error code attached to every packet since
294 // almost every errorcode will be KErrNone, we have a single error code per buffer
295 // If the error code is != KErrNone then it refers to the LAST packet in the buffer
296 TInt errorCode = KErrNone;
297 //Check the index, it's not equal to negative (-1) value defined in
298 //KUsbcInvalidBufferIndex.
299 __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0),
300 Kern::Fault(KUsbPanicLdd, __LINE__));
302 if (iError[iCurrentDrainingBufferIndex] != KErrNone)
304 // See if we are at the last packet
305 if ((iCurrentPacket + 1) == iNumberofPacketsRx[iCurrentDrainingBufferIndex])
307 errorCode = iError[iCurrentDrainingBufferIndex];
314 // used to decide whether a client read can complete straight away
315 TBool TDmaBuf::IsReaderEmpty()
317 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::IsReaderEmpty iTotalRxPacketsAvail=%d",
318 iTotalRxPacketsAvail));
319 return (iTotalRxPacketsAvail == 0);
323 void TDmaBuf::ReadXferComplete(TInt aNoBytesRecv, TInt aNoPacketsRecv, TInt aErrorCode)
325 // Adjust pending packet
326 if ((aNoBytesRecv == 0) && (aErrorCode != KErrNone))
328 // Make the buffer available for reuse
329 iDrainable[iCurrentFillingBufferIndex] = EFalse;
333 ModifyTotalRxBytesAvail(aNoBytesRecv);
334 ModifyTotalRxPacketsAvail(aNoPacketsRecv);
335 iNumberofBytesRx[iCurrentFillingBufferIndex] = aNoBytesRecv;
336 iNumberofPacketsRx[iCurrentFillingBufferIndex] = aNoPacketsRecv;
338 #if defined(USBC_LDD_BUFFER_TRACE)
339 iNumberofBytesRxRemain[iCurrentFillingBufferIndex] = aNoBytesRecv;
340 iNumberofPacketsRxRemain[iCurrentFillingBufferIndex] = aNoPacketsRecv;
343 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::ReadXferComplete 2 # of bytes=%d # of packets=%d",
344 iTotalRxBytesAvail, iTotalRxPacketsAvail));
345 iDrainable[iCurrentFillingBufferIndex] = ETrue;
346 iError[iCurrentFillingBufferIndex] = aErrorCode;
347 AddToDrainQueue(iCurrentFillingBufferIndex);
348 if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex)
350 NextDrainableBuffer();
355 TInt TDmaBuf::RxGetNextXfer(TUint8*& aBufferAddr, TUsbcPacketArray*& aIndexArray,
356 TUsbcPacketArray*& aSizeArray, TInt& aLength, TPhysAddr& aBufferPhys)
358 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer 1"));
361 __KTRACE_OPT(KUSB, Kern::Printf(" ---> RxIsActive, returning"));
365 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer Current buffer=%d",
366 iCurrentFillingBufferIndex));
367 if (iDrainable[iCurrentFillingBufferIndex])
369 // If the controller refused the last read request, then the current buffer will still be marked
370 // as !Drainable, because the controller never completed the read to the ldd. and therefore the buffer
372 if (!NextFillableBuffer())
378 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer New buffer=%d",
379 iCurrentFillingBufferIndex));
380 aBufferAddr = iBuffers[iCurrentFillingBufferIndex];
381 aBufferPhys = iBufferPhys[iCurrentFillingBufferIndex];
382 aIndexArray = iPacketIndex[iCurrentFillingBufferIndex];
383 aSizeArray = iPacketSize[iCurrentFillingBufferIndex];
386 #if defined(USBC_LDD_BUFFER_TRACE)
387 iFillingOrderArray[iCurrentFillingBufferIndex] = ++iFillingOrder;
394 TInt TDmaBuf::RxCopyPacketToClient(DThread* aThread, TClientBuffer *aTcb, TInt aLength)
396 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 1"));
398 #if defined(USBC_LDD_BUFFER_TRACE)
399 const TInt numPkts = NoRxPackets();
400 const TInt numPktsAlt = NoRxPacketsAlt();
401 const TInt numBytes = RxBytesAvailable();
402 const TInt numBytesAlt = NoRxBytesAlt();
404 if (numPkts != numPktsAlt)
407 "TDmaBuf::RxCopyPacketToClient: Error: #pkts mismatch global=%d actual=%d",
408 numPkts, numPktsAlt);
410 if (numBytes != numBytesAlt)
413 "TDmaBuf::RxCopyPacketToClient: Error: #bytes mismatch global=%d actual=%d",
414 numBytes, numBytesAlt);
416 if ((numPkts == 0) && (numBytes !=0))
419 "TDmaBuf::RxCopyPacketToClient: Error: global bytes & pkts mismatch pkts=%d bytes=%d",
422 if ((numPktsAlt == 0) && (numBytesAlt !=0))
425 "TDmaBuf::RxCopyPacketToClient: Error: actual bytes & pkts mismatch pkts=%d bytes=%d",
426 numPktsAlt, numBytesAlt);
433 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 2"));
434 // the next condition should be true because we have some packets available
435 // coverity[var_tested_neg]
436 if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex)
438 // Marked as Coverity "Intentional" as the member variable
439 // iCurrentDrainingBufferIndex is attentionaly negative, from previous
440 // initialization to KUsbcInvalidBufferIndex (which equals -1).
441 if (!NextDrainableBuffer())
445 __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0 ),
446 Kern::Fault(KUsbPanicLdd, __LINE__));
448 if (!iDrainable[iCurrentDrainingBufferIndex])
451 // Calculate copy-from address & adjust for the fact that
452 // some data may have already been read from the packet
453 TUint8* logicalSrc = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset;
454 TInt packetSz = iCurrentPacketSizeArray[iCurrentPacket];
455 TInt thisPacketSz = packetSz - iExtractOffset;
457 // try and sort out what a "packet" might mean.
458 // in a multi-packet dma environment, we might see super-packets
459 // i.e. we might just see one packet, maybe 4K or so long, made of lots of small packets
460 // Since we don't know where the packet boundaries will be, we have to assume that
461 // any 'packet' larger than the max packet size of the ep is, in fact, a conglomeration
462 // of smaller packets. However, for the purposes of the packet count, this is still regarded
463 // as a single packet and the packet count only decremented when it is consumed.
464 // As before, if the user fails to read an entire packet out then the next packet is moved onto anyway
465 // To be safe the user must always supply a buffer of at least max packet size bytes.
466 if (thisPacketSz > iMaxPacketSize)
468 // Multiple packets left in buffer
469 // calculate number of bytes to end of packet
470 if (iEndpointType == KUsbEpTypeBulk)
472 thisPacketSz = iMaxPacketSize - (iExtractOffset & (iMaxPacketSize - 1));
476 thisPacketSz = iMaxPacketSize - (iExtractOffset % iMaxPacketSize);
478 errorCode = KErrNone;
482 errorCode = GetCurrentError(); // single packet left
485 iExtractOffset += thisPacketSz; // iExtractOffset is now at the end of the real or notional packet
487 ModifyTotalRxBytesAvail(-thisPacketSz);
488 #if defined(USBC_LDD_BUFFER_TRACE)
489 iNumberofBytesRxRemain[iCurrentDrainingBufferIndex] -= thisPacketSz;
491 // this can only be untrue if the "packet" is a conglomeration of smaller packets:
492 if (iExtractOffset == packetSz)
494 // packet consumed, advance to next packet in buffer
495 #if defined(USBC_LDD_BUFFER_TRACE)
496 iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1;
501 TPtrC8 des(logicalSrc, thisPacketSz);
502 TInt r=Kern::ThreadBufWrite(aThread, aTcb, des, 0, 0, aThread);
507 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 3"));
509 FreeDrainedBuffers();
511 // Use this error code to complete client read request:
516 TInt TDmaBuf::RxCopyDataToClient(DThread* aThread, TClientBuffer *aTcb, TInt aLength, TUint32& aDestOffset,
517 TBool aRUS, TBool& aCompleteNow)
519 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyDataToClient 1"));
520 aCompleteNow = ETrue;
522 #if defined(USBC_LDD_BUFFER_TRACE)
523 const TInt numPkts = NoRxPackets();
524 const TInt numPktsAlt = NoRxPacketsAlt();
525 const TInt numBytes = RxBytesAvailable();
526 const TInt numBytesAlt = NoRxBytesAlt();
528 if (numPkts != numPktsAlt)
531 "TDmaBuf::RxCopyDataToClient: Error: #pkts mismatch global=%d actual=%d",
532 numPkts, numPktsAlt);
534 if (numBytes != numBytesAlt)
537 "TDmaBuf::RxCopyDataToClient: Error: #bytes mismatch global=%d actual=%d",
538 numBytes, numBytesAlt);
540 if ((numPkts == 0) && (numBytes != 0))
543 "TDmaBuf::RxCopyDataToClient: Error: global bytes & pkts mismatch pkts=%d bytes=%d",
546 if ((numPktsAlt == 0) && (numBytesAlt != 0))
549 "TDmaBuf::RxCopyDataToClient: Error: actual bytes & pkts mismatch pkts=%d bytes=%d",
550 numPktsAlt, numBytesAlt);
559 // coverity[var_tested_neg]
560 if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex)
562 // Marked as Coverity "Inentional" as the member variable
563 // iCurrentDrainingBufferIndex is attentionaly negative, from previous
564 // initialization to KUsbcInvalidBufferIndex (which equals -1).
566 if (!NextDrainableBuffer())
568 #if defined(USBC_LDD_BUFFER_TRACE)
569 Kern::Printf("TDmaBuf::RxCopyDataToClient: Error: No buffer draining=%d, packets=%d",
570 iCurrentDrainingBufferIndex, iTotalRxPacketsAvail);
575 #if defined(USBC_LDD_BUFFER_TRACE)
577 __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0 ),
578 Kern::Fault(KUsbPanicLdd, __LINE__));
580 if (iDrainingOrder != iFillingOrderArray[iCurrentDrainingBufferIndex])
582 Kern::Printf("!!! Out of Order Draining TDmaBuf::RxCopyDataToClient 10 draining=%d",
583 iCurrentDrainingBufferIndex);
586 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyDataToClient 2"));
588 TUint8* blockStartAddr = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset;
589 TUint8* lastEndAddr = blockStartAddr; // going to track the contiguity of the memory
590 TUint8* thisStartAddr = blockStartAddr;
591 TInt toDo = Min(aLength - (TInt)aDestOffset, iTotalRxBytesAvail);
592 #if defined(USBC_LDD_BUFFER_TRACE)
593 TInt bufnum = iCurrentDrainingBufferIndex;
595 TInt errorCode = KErrNone;
596 TBool isShortPacket = EFalse;
597 const TInt maxPacketSizeMask = iMaxPacketSize - 1;
600 #if defined(USBC_LDD_BUFFER_TRACE)
601 if (bufnum != iCurrentDrainingBufferIndex)
603 bufnum = iCurrentDrainingBufferIndex;
604 if (iDrainingOrder != iFillingOrderArray[iCurrentDrainingBufferIndex])
606 Kern::Printf("!!! Out of Order Draining TDmaBuf::RxCopyDataToClient 20 draining=%d",
607 iCurrentDrainingBufferIndex);
611 if (errorCode == KErrNone)
613 errorCode = GetCurrentError();
615 thisStartAddr = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset;
616 const TInt thisPacketSize = iCurrentPacketSizeArray[iCurrentPacket];
617 const TInt size = thisPacketSize - iExtractOffset;
620 if (iEndpointType == KUsbEpTypeBulk)
622 isShortPacket = (size < iMaxPacketSize) || (size & maxPacketSizeMask);
626 // this 'if' block is arranged to avoid a division on packet sizes <= iMaxPacketSize
627 isShortPacket = (size < iMaxPacketSize) ||
628 ((size > iMaxPacketSize) && (size % iMaxPacketSize));
631 TInt copySize = Min(size, toDo);
632 iExtractOffset += copySize;
634 if (thisStartAddr != lastEndAddr)
636 TInt bytesToCopy = lastEndAddr - blockStartAddr;
637 TInt r=CopyToUser(aThread, blockStartAddr, bytesToCopy, aTcb, aDestOffset);
639 Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat);
640 blockStartAddr = thisStartAddr;
643 ModifyTotalRxBytesAvail(-copySize);
644 #if defined(USBC_LDD_BUFFER_TRACE)
645 iNumberofBytesRxRemain[iCurrentDrainingBufferIndex] -= copySize;
647 lastEndAddr = thisStartAddr + copySize;
648 if (iExtractOffset == thisPacketSize)
650 // More data to copy, so need to access new packet
651 #if defined(USBC_LDD_BUFFER_TRACE)
652 iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1;
654 if (!AdvancePacket())
656 break; // no more packets left
659 } while (toDo > 0 && !isShortPacket);
661 if (thisStartAddr != lastEndAddr)
663 TInt bytesToCopy = lastEndAddr - blockStartAddr;
664 TInt r=CopyToUser(aThread, blockStartAddr, bytesToCopy, aTcb, aDestOffset);
666 Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat);
669 // If we have transferred the requested amount of data it is still possible that
670 // the next packet is a zlp which needs to be bumped over
672 if (aRUS && (toDo == 0) && (iExtractOffset == 0) && (!isShortPacket) && (!IsReaderEmpty()) &&
673 (PeekNextPacketSize() == 0))
676 isShortPacket = ETrue;
677 #if defined(USBC_LDD_BUFFER_TRACE)
678 iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1;
682 aCompleteNow = isShortPacket || (((TInt)aDestOffset) == aLength) || (errorCode != KErrNone);
684 FreeDrainedBuffers();
686 // Use this error code to complete client read request
691 inline TInt TDmaBuf::CopyToUser(DThread* aThread, const TUint8* aSourceAddr,
692 TInt aLength, TClientBuffer *aTcb, TUint32& aDestOffset)
694 TPtrC8 des(aSourceAddr, aLength);
695 TInt errorCode = Kern::ThreadBufWrite(aThread, aTcb, des, aDestOffset, KChunkShiftBy0, aThread);
696 if (errorCode == KErrNone)
698 aDestOffset += aLength;
704 inline TInt TDmaBuf::NoRxPackets() const
706 return iTotalRxPacketsAvail;
710 inline void TDmaBuf::IncrementBufferIndex(TInt& aIndex)
712 if (++aIndex == iNumberofBuffers)
717 TBool TDmaBuf::NextDrainableBuffer()
720 if (iCurrentDrainingBufferIndex != KUsbcInvalidBufferIndex)
722 iCanBeFreed[iCurrentDrainingBufferIndex] = ETrue;
723 iNumberofPacketsRx[iCurrentDrainingBufferIndex] = 0; // Current buffer is empty
724 iNumberofBytesRx[iCurrentDrainingBufferIndex] = 0; // Current buffer is empty
726 #if defined(USBC_LDD_BUFFER_TRACE)
727 TUint& bytesRemain = iNumberofBytesRxRemain[iCurrentDrainingBufferIndex];
728 TUint& pktsRemain = iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex];
729 if ((bytesRemain != 0) || (pktsRemain != 0))
732 "TDmaBuf::NextDrainableBuffer: Error: data discarded buffer=%d pkts=%d bytes=%d",
733 iCurrentDrainingBufferIndex, pktsRemain, bytesRemain);
739 iCurrentDrainingBufferIndex = KUsbcInvalidBufferIndex;
740 iCurrentPacket = KUsbcInvalidPacketIndex;
743 if (iDrainQueueIndex != KUsbcInvalidDrainQueueIndex)
746 const TInt index = iDrainQueue[0];
748 for (TInt i = 0; i < iNumberofBuffers; i++)
750 iDrainQueue[i] = iDrainQueue[i+1];
753 #if defined(USBC_LDD_BUFFER_TRACE)
754 if (index != KUsbcInvalidBufferIndex)
758 iCurrentDrainingBufferIndex = index;
759 iCurrentDrainingBuffer = iBuffers[index];
760 iCurrentPacketIndexArray = iPacketIndex[index];
761 iCurrentPacketSizeArray = iPacketSize[index];
768 TInt TDmaBuf::PeekNextDrainableBuffer()
770 TInt r = KUsbcInvalidBufferIndex;
771 if (iDrainQueueIndex != KUsbcInvalidDrainQueueIndex)
779 TBool TDmaBuf::NextFillableBuffer()
782 TInt index = iCurrentFillingBufferIndex;
783 IncrementBufferIndex(index);
784 // the sequence will restart at 0 if a buffer can't be found this time
785 iCurrentFillingBufferIndex = 0;
786 for (TInt i = 0; i < iNumberofBuffers; i++)
788 if (!iDrainable[index])
790 iCurrentFillingBufferIndex = index;
794 IncrementBufferIndex(index);
800 void TDmaBuf::FreeDrainedBuffers()
802 for (TInt i = 0; i < iNumberofBuffers; i++)
804 if (iDrainable[i] && iCanBeFreed[i])
806 iDrainable[i] = iCanBeFreed[i] = EFalse;
812 TBool TDmaBuf::ShortPacketExists()
814 // Actually, a short packet or residue data
815 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::ShortPacketExists 1"));
816 TInt index = iCurrentDrainingBufferIndex;
817 TUsbcPacketArray* pktSizeArray = iCurrentPacketSizeArray;
819 if (iMaxPacketSize > 0)
821 // No buffers available for draining
822 if ((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) ||
823 (iCurrentPacket == KUsbcInvalidPacketIndex))
826 // Zlp waiting at tail
827 if ((iTotalRxBytesAvail == 0) && (NoRxPackets() == 1))
830 if (iEndpointType == KUsbEpTypeBulk)
832 const TInt mask = iMaxPacketSize - 1;
833 if (iTotalRxBytesAvail & mask)
836 // residue==0; this can be because
837 // zlps exist, or short packets combine to n * max_packet_size
838 // This means spadework
839 const TInt s = iCurrentPacketSizeArray[iCurrentPacket] - iExtractOffset;
840 if ((s == 0) || (s & mask))
845 for (TInt i = 0; i < iNumberofBuffers; i++)
847 if (index == KUsbcInvalidBufferIndex)
849 if (iDrainable[index])
851 const TInt packetCount = iNumberofPacketsRx[index];
852 const TInt lastPacketSize=pktSizeArray[packetCount - 1];
853 if ((lastPacketSize < iMaxPacketSize) || (lastPacketSize & mask))
858 index = iDrainQueue[i];
859 pktSizeArray = iPacketSize[index];
864 if (iTotalRxBytesAvail % iMaxPacketSize)
867 // residue==0; this can be because
868 // zlps exist, or short packets combine to n * max_packet_size
869 // This means spadework
870 const TInt s = iCurrentPacketSizeArray[iCurrentPacket] - iExtractOffset;
871 if ((s == 0) || (s % iMaxPacketSize))
876 for (TInt i = 0; i < iNumberofBuffers; i++)
878 if (index == KUsbcInvalidBufferIndex)
880 if (iDrainable[index])
882 const TInt packetCount = iNumberofPacketsRx[index];
883 const TInt lastPacketSize = pktSizeArray[packetCount - 1];
884 if ((lastPacketSize < iMaxPacketSize) || (lastPacketSize % iMaxPacketSize))
889 index = iDrainQueue[i];
890 pktSizeArray = iPacketSize[index];
899 void TDmaBuf::AddToDrainQueue(TInt aBufferIndex)
901 if (iDrainQueue[iDrainQueueIndex + 1] != KUsbcInvalidBufferIndex)
903 #if defined(USBC_LDD_BUFFER_TRACE)
904 Kern::Printf("TDmaBuf::AddToDrainQueue: Error: invalid iDrainQueue[x]");
907 iDrainQueue[++iDrainQueueIndex] = aBufferIndex;
911 #if defined(USBC_LDD_BUFFER_TRACE)
912 TInt TDmaBuf::NoRxPacketsAlt() const
915 for(TInt i = 0; i < iNumberofBuffers; i++)
919 pktCount += iNumberofPacketsRxRemain[i];
926 TInt TDmaBuf::NoRxBytesAlt() const
929 for(TInt i = 0; i < iNumberofBuffers; i++)
933 byteCount += iNumberofBytesRxRemain[i];
941 // We only store 1 transaction, no other buffering is done
942 TInt TDmaBuf::TxStoreData(DThread* aThread, TClientBuffer *aTcb, TInt aTxLength, TUint32 aBufferOffset)
944 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::TxStoreData 1"));
945 if (!IsReaderEmpty())
948 __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::TxStoreData 2"));
950 TInt remainTxLength = aTxLength;
951 TUint32 bufferOffset = aBufferOffset;
952 // Store each buffer separately
953 for( TInt i=0;(i<iNumberofBuffers)&&(remainTxLength>0);i++)
955 TUint8* logicalDest = iBuffers[i];
956 TInt xferSz = Min(remainTxLength, iBufSz);
957 TPtr8 des(logicalDest, xferSz, xferSz);
958 TInt r = Kern::ThreadBufRead(aThread, aTcb, des, bufferOffset, KChunkShiftBy0);
961 Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat);
964 remainTxLength -= iBufSz;
965 bufferOffset += iBufSz;
972 TInt TDmaBuf::TxGetNextXfer(TUint8*& aBufferAddr, TInt& aTxLength, TPhysAddr& aBufferPhys)
977 aBufferAddr = iBuffers[0]; // only 1 tx buffer
978 aBufferPhys = iBufferPhys[0];
979 aTxLength = BufferTotalSize();