AppleUSBOHCI_Interrupts.cpp [plain text]
#include "AppleUSBOHCI.h"
#include <libkern/OSByteOrder.h>
#include <IOKit/usb/IOUSBLog.h>
#define nil (0)
#define DEBUGGING_LEVEL 0 // 1 = low; 2 = high; 3 = extreme
#define super IOUSBController
#define self this
void AppleUSBOHCI::PollInterrupts(IOUSBCompletionAction safeAction)
{
UInt64 timeElapsed;
absolutetime_to_nanoseconds(_filterTimeStamp2, &_timeElapsed);
if (_writeDoneHeadInterrupt & kOHCIHcInterrupt_WDH)
{
_writeDoneHeadInterrupt = 0;
UIMProcessDoneQueue(safeAction);
}
if (_resumeDetectedInterrupt & kOHCIHcInterrupt_RD)
{
_resumeDetectedInterrupt = 0;
_remote_wakeup_occurred = true;
USBLog(3,"%s[%p] ResumeDetected Interrupt on bus %d", getName(), this, _busNumber );
if ( _idleSuspend )
setPowerState(kOHCISetPowerLevelRunning, self);
}
if (_unrecoverableErrorInterrupt & kOHCIHcInterrupt_UE)
{
_unrecoverableErrorInterrupt = 0;
_errors.unrecoverableError++;
_pOHCIRegisters->hcCommandStatus = USBToHostLong(kOHCIHcCommandStatus_HCR);
delay(10 * MICROSECOND);
_pOHCIRegisters->hcControl = USBToHostLong((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase) | kOHCIHcControl_PLE);
}
if (_rootHubStatusChangeInterrupt & kOHCIHcInterrupt_RHSC)
{
_rootHubStatusChangeInterrupt = 0;
_remote_wakeup_occurred = true;
USBLog(3,"%s[%p] RootHub Status Change Interrupt on bus %d", getName(), this, _busNumber );
UIMRootHubStatusChange( false );
LastRootHubPortStatusChanged ( true );
_pOHCIRegisters->hcInterruptEnable = HostToUSBLong(kOHCIHcInterrupt_RHSC);
IOSync();
}
}
void AppleUSBOHCI::InterruptHandler(OSObject *owner,
IOInterruptEventSource * ,
int )
{
register AppleUSBOHCI *controller = (AppleUSBOHCI *) owner;
if (!controller || controller->isInactive() || (controller->_onCardBus && controller->_pcCardEjected) || !controller->_ohciAvailable)
return;
controller->finishPending();
controller->PollInterrupts();
controller->_filterInterruptCount = 0;
}
bool
AppleUSBOHCI::PrimaryInterruptFilter(OSObject *owner, IOFilterInterruptEventSource *source)
{
register AppleUSBOHCI *controller = (AppleUSBOHCI *)owner;
bool result = true;
if (!controller || controller->isInactive() || (controller->_onCardBus && controller->_pcCardEjected) || !controller->_ohciAvailable)
return false;
result = controller->FilterInterrupt(0);
return result;
}
bool
AppleUSBOHCI::FilterInterrupt(int index)
{
register UInt32 activeInterrupts;
register UInt32 enabledInterrupts;
IOPhysicalAddress physicalAddress;
OHCIGeneralTransferDescriptorPtr pHCDoneTD;
OHCIGeneralTransferDescriptorPtr nextTD, prevTD;
AbsoluteTime timeStamp;
UInt32 numberOfTDs = 0;
IOPhysicalAddress oldHead;
IOPhysicalAddress cachedHead;
UInt32 cachedProducer;
Boolean needSecondary = false;
enabledInterrupts = USBToHostLong(_pOHCIRegisters->hcInterruptEnable);
activeInterrupts = enabledInterrupts & USBToHostLong(_pOHCIRegisters->hcInterruptStatus);
if ((enabledInterrupts & kOHCIHcInterrupt_MIE) && (activeInterrupts != 0))
{
if (activeInterrupts & kOHCIHcInterrupt_FNO)
{
_errors.frameNumberOverflow++;
if ( (USBToHostWord(*(UInt16*)(_pHCCA + kHCCAFrameNumberOffset)) & kOHCIFmNumberMask) < kOHCIBit15 )
_frameNumber += kOHCIFrameOverflowBit;
_pOHCIRegisters->hcInterruptStatus = HostToUSBLong(kOHCIHcInterrupt_FNO);
IOSync();
}
if (activeInterrupts & kOHCIHcInterrupt_SO)
{
_errors.scheduleOverrun++;
_pOHCIRegisters->hcInterruptStatus = HostToUSBLong(kOHCIHcInterrupt_SO);
IOSync();
}
if (activeInterrupts & kOHCIHcInterrupt_SF)
{
_pOHCIRegisters->hcInterruptStatus = HostToUSBLong(kOHCIHcInterrupt_SF);
IOSync();
_pOHCIRegisters->hcInterruptDisable = HostToUSBLong(kOHCIHcInterrupt_SF);
IOSync();
}
if (activeInterrupts & kOHCIHcInterrupt_OC)
{
_errors.ownershipChange++;
_pOHCIRegisters->hcInterruptStatus = HostToUSBLong(kOHCIHcInterrupt_OC);
IOSync();
}
if (activeInterrupts & kOHCIHcInterrupt_RHSC)
{
_rootHubStatusChangeInterrupt = kOHCIHcInterrupt_RHSC;
_pOHCIRegisters->hcInterruptDisable = HostToUSBLong(kOHCIHcInterrupt_RHSC);
IOSync();
_pOHCIRegisters->hcInterruptStatus = HostToUSBLong(kOHCIHcInterrupt_RHSC);
IOSync();
needSecondary = true;
}
if (activeInterrupts & kOHCIHcInterrupt_UE)
{
_errors.unrecoverableError++;
_unrecoverableErrorInterrupt = kOHCIHcInterrupt_UE;
_pOHCIRegisters->hcInterruptStatus = HostToUSBLong(kOHCIHcInterrupt_UE);
IOSync();
needSecondary = true;
}
if (activeInterrupts & kOHCIHcInterrupt_RD)
{
_resumeDetectedInterrupt = kOHCIHcInterrupt_RD;
_pOHCIRegisters->hcInterruptStatus = HostToUSBLong(kOHCIHcInterrupt_RD);
IOSync();
needSecondary = true;
}
if (activeInterrupts & kOHCIHcInterrupt_WDH)
{
clock_get_uptime(&timeStamp);
_filterInterruptCount++;
_filterTimeStamp2 = timeStamp;
SUB_ABSOLUTETIME(&_filterTimeStamp2, &_filterTimeStamp);
_filterTimeStamp = timeStamp;
physicalAddress = (UInt32) USBToHostLong(*(UInt32 *)(_pHCCA + kHCCADoneHeadOffset));
physicalAddress &= kOHCIHeadPMask;
oldHead = _savedDoneQueueHead;
cachedHead = physicalAddress;
pHCDoneTD = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress(physicalAddress);
*(UInt32 *)(_pHCCA + kHCCADoneHeadOffset) = 0L;
_pOHCIRegisters->hcInterruptStatus = HostToUSBLong(kOHCIHcInterrupt_WDH);
IOSync();
_writeDoneHeadInterrupt = kOHCIHcInterrupt_WDH;
prevTD = NULL;
while (pHCDoneTD != NULL)
{
OHCIIsochTransferDescriptorPtr pITD;
IOUSBLowLatencyIsocFrame * pFrames;
IOReturn errStatus;
UInt32 control;
UInt32 transferStatus;
UInt32 frameCount;
UInt32 i;
numberOfTDs++;
physicalAddress = USBToHostLong(pHCDoneTD->nextTD) & kOHCIHeadPMask;
nextTD = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress(physicalAddress);
if ( (pHCDoneTD->pType == kOHCIIsochronousInLowLatencyType) ||
(pHCDoneTD->pType == kOHCIIsochronousOutLowLatencyType) )
{
_lowLatencyIsochTDsProcessed++;
pITD = (OHCIIsochTransferDescriptorPtr) pHCDoneTD;
pFrames = (IOUSBLowLatencyIsocFrame *) pITD->pIsocFrame;
control = USBToHostLong(pHCDoneTD->ohciFlags);
transferStatus = (control & kOHCIGTDControl_CC) >> kOHCIGTDControl_CCPhase;
errStatus = TranslateStatusToUSBError(transferStatus);
frameCount = (USBToHostLong(pITD->flags) & kOHCIITDControl_FC) >> kOHCIITDControl_FCPhase;
for (i = 0; i <= frameCount; i++)
{
_framesUpdated++;
if ( pFrames[pITD->frameNum + i].frStatus != (IOReturn) kUSBLowLatencyIsochTransferKey )
_framesError++;
pFrames[pITD->frameNum + i].frTimeStamp = timeStamp;
UInt16 offset = USBToHostWord(pITD->offset[i]);
if ( ((offset & kOHCIITDOffset_CC) >> kOHCIITDOffset_CCPhase) == kOHCIITDOffsetConditionNotAccessed)
{
pFrames[pITD->frameNum + i].frActCount = 0;
pFrames[pITD->frameNum + i].frStatus = TranslateStatusToUSBError(kOHCIITDConditionNotAccessedReturn);
}
else
{
pFrames[pITD->frameNum + i].frStatus = TranslateStatusToUSBError( (offset & kOHCIITDPSW_CC) >> kOHCIITDPSW_CCPhase);
if((kIOReturnSuccess == pFrames[pITD->frameNum + i].frStatus) && (pITD->pType == kOHCIIsochronousOutLowLatencyType))
pFrames[pITD->frameNum + i].frActCount = pFrames[pITD->frameNum + i].frReqCount;
else
pFrames[pITD->frameNum + i].frActCount = offset & kOHCIITDPSW_Size;
}
}
}
prevTD = pHCDoneTD;
pHCDoneTD = nextTD;
}
cachedProducer = _producerCount;
cachedProducer += numberOfTDs;
if ( prevTD != NULL )
prevTD->nextTD = HostToUSBLong(oldHead);
IOSimpleLockLock( _wdhLock );
_savedDoneQueueHead = cachedHead; _producerCount = cachedProducer;
IOSimpleLockUnlock( _wdhLock );
needSecondary = true;
}
}
if (needSecondary)
_filterInterruptSource->signalInterrupt();
return false;
}