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