📄 appleusbohci.cpp
字号:
if ( _lowLatencyIsochTDsProcessed != 0 ) { USBLog(6, "%s[%p]::ProcessCompletedITD: LowLatency isoch TD's proccessed: %d, framesUpdated: %d, framesError: %d", getName(), this, _lowLatencyIsochTDsProcessed, _framesUpdated, _framesError); USBLog(7, "%s[%p]::ProcessCompletedITD: delay in microsecs before callback (from hw interrupt time): %ld", getName(), this, (UInt32) timeElapsed / 1000); // SUB_ABSOLUTETIME(&_filterTimeStamp2, &_filterTimeStamp); // absolutetime_to_nanoseconds(_filterTimeStamp2, &timeElapsed); // USBLog(7, "%s[%p]::ProcessCompletedITD: filter interrupt duration: %ld", getName(), this, (UInt32) timeElapsed / 1000); } // These need to be updated only when we process a TD due to an interrupt // _lowLatencyIsochTDsProcessed = 0; _framesUpdated = 0; _framesError = 0; } for (i=0; i <= frameCount; i++) { // Need to process low latency isoch differently than other isoc, as the frameList has an extra parameter (use pLLFrame instead of pFrame ) // if ( (pITD->pType == kOHCIIsochronousInLowLatencyType) || (pITD->pType == kOHCIIsochronousOutLowLatencyType) ) { UInt16 offset = USBToHostWord(pITD->pShared->offset[i]); // Check to see if we really processed this itd before: // if ( (_filterInterruptCount != 0 ) && ( (pITD->pType == kOHCIIsochronousInLowLatencyType) || (pITD->pType == kOHCIIsochronousOutLowLatencyType) ) ) { if ( (pLLFrames[pITD->frameNum + i].frStatus != (IOReturn) kUSBLowLatencyIsochTransferKey) ) { // USBLog(7,"%s[%p]::ProcessCompletedITD: frame processed at hw interrupt time: frame: %d, frReqCount: %d, frActCount: %d, frStatus: 0x%x frTimeStamp.lo: 0x%x", getName(), this, i, pLLFrames[pITD->frameNum + i].frReqCount, pLLFrames[pITD->frameNum + i].frActCount, pLLFrames[pITD->frameNum + i].frStatus, pLLFrames[pITD->frameNum + i].frTimeStamp.lo); USBLog(6,"%s[%p]::ProcessCompletedITD: frame processed at hw interrupt time: frame: %d, frTimeStamp.lo: 0x%x", getName(), this, i, pLLFrames[pITD->frameNum + i].frTimeStamp.lo); } } if ( ((offset & kOHCIITDOffset_CC) >> kOHCIITDOffset_CCPhase) == kOHCIITDOffsetConditionNotAccessed) { USBLog(6,"%s[%p]::ProcessCompletedITD: Isoch frame not accessed. Frame in request(1 based) %d, IsocFramePtr: %p, ITD: %p, Frames in this TD: %d, Relative frame in TD: %d", getName(), this, pITD->frameNum + i + 1, pLLFrames, pITD, frameCount+1, i+1); pLLFrames[pITD->frameNum + i].frActCount = 0; pLLFrames[pITD->frameNum + i].frStatus = kOHCIITDConditionNotAccessedReturn; } else { pLLFrames[pITD->frameNum + i].frStatus = (offset & kOHCIITDPSW_CC) >> kOHCIITDPSW_CCPhase; // Successful isoch transmit sets the size field to zero, // successful receive sets size to actual packet size received. if ( (kIOReturnSuccess == pLLFrames[pITD->frameNum + i].frStatus) && ( (pITD->pType == kOHCIIsochronousOutType) || (pITD->pType == kOHCIIsochronousOutLowLatencyType) ) ) pLLFrames[pITD->frameNum + i].frActCount = pLLFrames[pITD->frameNum + i].frReqCount; else pLLFrames[pITD->frameNum + i].frActCount = offset & kOHCIITDPSW_Size; } // Translate the OHCI Condition to one of the appropriate USB errors. We use aggregateStatus to determine // later on whether there was an error in any of the frames. If there was, then we set the completion error // to that reported in the aggregateStatus. There is no priority in the aggregateStatus except that if there // is a data underrun AND another type of error, then we report the "other" error. // frameStatus = pLLFrames[pITD->frameNum + i].frStatus; if ( frameStatus != kIOReturnSuccess ) { pLLFrames[pITD->frameNum + i].frStatus = TranslateStatusToUSBError(frameStatus); if ( pLLFrames[pITD->frameNum + i].frStatus == kIOReturnUnderrun ) hadUnderrun = true; else aggregateStatus = pLLFrames[pITD->frameNum + i].frStatus; } } else { // Process non-low latency isoch // UInt16 offset = USBToHostWord(pITD->pShared->offset[i]); if ( ((offset & kOHCIITDOffset_CC) >> kOHCIITDOffset_CCPhase) == kOHCIITDOffsetConditionNotAccessed) { USBLog(6,"%s[%p]::ProcessCompletedITD: Isoch frame not accessed. Frame in request(1 based) %d, IsocFramePtr: %p, ITD: %p, Frames in this TD: %d, Relative frame in TD: %d", getName(), this, pITD->frameNum + i + 1, pFrames, pITD, frameCount+1, i+1); pFrames[pITD->frameNum + i].frActCount = 0; pFrames[pITD->frameNum + i].frStatus = kOHCIITDConditionNotAccessedReturn; } else { pFrames[pITD->frameNum + i].frStatus = (offset & kOHCIITDPSW_CC) >> kOHCIITDPSW_CCPhase; // Successful isoch transmit sets the size field to zero, // successful receive sets size to actual packet size received. if ( (kIOReturnSuccess == pFrames[pITD->frameNum + i].frStatus) && ( (pITD->pType == kOHCIIsochronousOutType) || (pITD->pType == kOHCIIsochronousOutLowLatencyType) ) ) pFrames[pITD->frameNum + i].frActCount = pFrames[pITD->frameNum + i].frReqCount; else pFrames[pITD->frameNum + i].frActCount = offset & kOHCIITDPSW_Size; } // Translate the OHCI Condition to one of the appropriate USB errors. We use aggregateStatus to determine // later on whether there was an error in any of the frames. If there was, then we set the completion error // to that reported in the aggregateStatus. There is no priority in the aggregateStatus except that if there // is a data underrun AND another type of error, then we report the "other" error. // frameStatus = pFrames[pITD->frameNum + i].frStatus; if ( frameStatus != kIOReturnSuccess ) { pFrames[pITD->frameNum + i].frStatus = TranslateStatusToUSBError(frameStatus); if ( pFrames[pITD->frameNum + i].frStatus == kIOReturnUnderrun ) hadUnderrun = true; else aggregateStatus = pFrames[pITD->frameNum + i].frStatus; } } } // call callback // if (pITD->completion.action) { IOUSBIsocCompletionAction pHandler; // If we had an error in any of the frames, then report that error as the status for this framelist // if ( (status == kIOReturnSuccess) && ( (aggregateStatus != kIOReturnSuccess) || hadUnderrun) ) { // If we don't have an aggregateStatus but we did have an underrun, then report the underrun // if ( (aggregateStatus == kIOReturnSuccess) && hadUnderrun ) aggregateStatus = kIOReturnUnderrun; USBLog(6, "%s[%p]::ProcessCompletedITD: Changing isoc completion error from success to 0x%x", getName(), this, aggregateStatus); status = aggregateStatus; } // Zero out handler first than call it // // USBLog(7,"%s[%p]::ProcessCompletedITD: calling completion", getName(), this, pITD); pHandler = pITD->completion.action; pITD->completion.action = NULL; (*pHandler) (pITD->completion.target, pITD->completion.parameter, status, pFrames); }}void AppleUSBOHCI::UIMProcessDoneQueue(IOUSBCompletionAction safeAction){ UInt32 interruptStatus; IOPhysicalAddress PhysAddr; AppleOHCIGeneralTransferDescriptorPtr pHCDoneTD; UInt32 cachedProducer; IOPhysicalAddress cachedWriteDoneQueueHead; IOInterruptState intState; // Get the values of the Done Queue Head and the producer count. We use a lock and disable interrupts // so that the filter routine does not preempt us and updates the values while we're trying to read them. // intState = IOSimpleLockLockDisableInterrupt( _wdhLock ); cachedWriteDoneQueueHead = _savedDoneQueueHead; cachedProducer = _producerCount; IOSimpleLockUnlockEnableInterrupt( _wdhLock, intState ); // OK, now that we have a valid queue head in cachedWriteDoneQueueHead, let's process the list // DoDoneQueueProcessing( cachedWriteDoneQueueHead, cachedProducer, safeAction); return;}IOReturnAppleUSBOHCI::DoDoneQueueProcessing(IOPhysicalAddress cachedWriteDoneQueueHead, UInt32 cachedProducer, IOUSBCompletionAction safeAction){ UInt32 control, transferStatus; long bufferSizeRemaining; AppleOHCIGeneralTransferDescriptorPtr pHCDoneTD, prevTD, nextTD; IOPhysicalAddress physicalAddress; UInt32 pageMask; AppleOHCIEndpointDescriptorPtr tempED; AppleOHCIIsochTransferDescriptorPtr pITD, testITD; volatile UInt32 cachedConsumer; UInt32 numTDs = 0; // This should never happen // if (cachedWriteDoneQueueHead == NULL) return kIOReturnSuccess; // Cache our consumer count // cachedConsumer = _consumerCount; // If for some reason our cachedConsumer and cachedProducer are the same, then we need to bail out, as we // don't have anything to process // if ( cachedConsumer == cachedProducer) { USBLog(3, "%s[%p]::DoDoneQueueProcessing consumer (%d) == producer (%d) Filter count: %d", getName(), this, cachedConsumer, cachedProducer, _filterInterruptCount); return kIOReturnSuccess; } // Get the logical address for our cachedQueueHead // pHCDoneTD = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(cachedWriteDoneQueueHead); if ( pHCDoneTD == NULL ) return kIOReturnSuccess; // Now, reverse the queue. We know how many TD's to process, not by the last one pointing to NULL, // but by the fact that cachedConsumer != cachedProducer. So, go through the loop and increment consumer // until they are equal, taking care or the wraparound case. // prevTD = NULL; while ( true ) { pHCDoneTD->pLogicalNext = prevTD; prevTD = pHCDoneTD; numTDs++; // Increment our consumer count. If we wrap around, then increment again. If we reach // the end (both counts are equal, then brake out of the loop // cachedConsumer++; if ( cachedProducer == cachedConsumer) break; physicalAddress = USBToHostLong(pHCDoneTD->pShared->nextTD) & kOHCIHeadPMask; nextTD = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(physicalAddress); if ( nextTD == NULL ) { USBLog(5, "%s[%p]::DoDoneQueueProcessing nextTD = NULL. (%p, %d, %d, %d)", getName(), this, physicalAddress, _filterInterruptCount, cachedProducer, cachedConsumer); break; } pHCDoneTD = nextTD; } // New done queue head // pHCDoneTD = prevTD; // Update our consumer count // _consumerCount = cachedConsumer; // Now, we have a new done queue head. Now process this reversed list in LOGICAL order. That // means that we can look for a NULL termination // while (pHCDoneTD != NULL) { // USBLog(6, "%s[%p]::DoDoneQueueProcessing", getName(), this); // print_td(pHCDoneTD); IOReturn errStatus; // find the next one nextTD = pHCDoneTD->pLogicalNext; control = USBToHostLong(pHCDoneTD->pShared->ohciFlags); transferStatus = (control & kOHCIGTDControl_CC) >> kOHCIGTDControl_CCPhase; errStatus = TranslateStatusToUSBError(transferStatus); if (_OptiOn && (pHCDoneTD->pType == kOHCIOptiLSBug)) { // clear any bad errors tempED = (AppleOHCIEndpointDescriptorPtr) pHCDoneTD->pEndpoint; pHCDoneTD->pShared->ohciFlags = pHCDoneTD->pShared->ohciFlags & HostToUSBLong(kOHCIGTDClearErrorMask); tempED->pShared->tdQueueHeadPtr &= HostToUSBLong(kOHCIHeadPMask); pHCDoneTD->pShared->nextTD = tempED->pShared->tdQueueTailPtr & HostToUSBLong(kOHCIHeadPMask); tempED->pShared->tdQueueTailPtr = HostToUSBLong(pHCDoneTD->pPhysical); _pOHCIRegisters->hcCommandStatus = HostToUSBLong (kOHCIHcCommandStatus_CLF); // For CMD Buffer Underrun Errata } else if ((transferStatus == kOHCIGTDConditionBufferUnderrun) && (pHCDoneTD->pType == kOHCIBulkTransferOutType) && (_errataBits & kErrataRetryBufferUnderruns)) { tempED = (AppleOHCIEndpointDescriptorPtr) pHCDoneTD->pEndpoint; pHCDoneTD->pShared->ohciFlags = pHCDoneTD->pShared->ohciFlags & HostToUSBLong(kOHCIGTDClearErrorMask); pHCDoneTD->pShared->nextTD = tempED->pShared->tdQueueHeadPtr & HostToUSBLong(kOHCIHeadPMask); pHCDoneTD->pLogicalNext = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(USBToHostLong(tempED->pShared->tdQueueHeadPtr) & kOHCIHeadPMask); tempED->pShared->tdQueueHeadPtr = USBToHostLong(pHCDoneTD->pPhysical) | (tempED->pShared->tdQueueHeadPtr & HostToUSBLong( kOHCIEDToggleBitMask)); _pOHCIRegisters->hcCommandStatus = HostToUSBLong(kOHCIHcCommandStatus_BLF); } else if ( (pHCDoneTD->pType == kOHCIIsochronousInType) || (pHCDoneTD->pType == kOHCIIsochronousOutType) || (pHCDoneTD->pType == kOHCIIsochronousInLowLatencyType) || (pHCDoneTD->pType == kOHCIIsochronousOutLowLatencyType) ) { // cast to a isoc type pITD = (AppleOHCIIsochTransferDescriptorPtr) pHCDoneTD; ProcessCompletedITD(pITD, errStatus); // deallocate td DeallocateITD(pITD); } else { bufferSizeRemaining = findBufferRemaining (pHCDoneTD); // if (pHCDoneTD->completion.action != NULL) if (pHCDoneTD->uimFlags & kUIMFlagsCallbackTD) { IOUSBCompletion completion = pHCDoneTD->command->GetUSLCompletion(); if(!safeAction || (safeAction == completion.action)) { // remove flag before completing pHCDoneTD->uimFlags &= ~kUIMFlagsCallbackTD; Complete(completion, errStatus, bufferSizeRemaining); DeallocateTD(pHCDoneTD); } else { if(_pendingHead) _pendingTail->pLogicalNext = pHCDoneTD; else _pendingHead = pHCDoneTD; _pendingTail = pHCDoneTD; } } else { if (errStatus != kIOReturnSuccess) { USBLog(5, "AppleUSBOHCI::DoDoneQueueProcessing - processing a short packet"); doCallback(pHCDoneTD, transferStatus, bufferSizeRemaining); } DeallocateTD(pHCDoneTD); } } pHCDoneTD = nextTD; /* New qHead */ } return(kIOReturnSuccess);}void AppleUSBOHCI::finishPending(){ while(_pendingHead) { AppleOHCIGeneralTransferDescriptorPtr next = _pendingHead->pLogicalNext; long bufferSizeRemaining = findBufferRemaining (_pendingHead); UInt32 transferStatus = (USBToHostLong(_pendingHead->pShared->ohciFlags) & kOHCIGTDControl_CC) >> kOHCIGTDControl_CCPhase; if (_pendingHead->uimFlags & kUIMFlagsCallbackTD) { IOUSBCompletion completion = _pendingHead->command->GetUSLCompletion(); _pendingHead->uimFlags &= ~kUIMFlagsCallbackTD; Complete(completion, TranslateStatusToUSBError(transferStatus), bufferSizeRemaining); } DeallocateTD(_pendingHead); _pendingHead = next; }}UInt32 AppleUSBOHCI::GetBandwidthAvailable(){ return _isochBandwidthAvail;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -