AppleUSBUHCI_Interrupts.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include "AppleUSBUHCI.h"
#include "AppleUHCIListElement.h"
#define super IOUSBControllerV2
#define self this
#pragma mark Interrupts
void
AppleUSBUHCI::PollInterrupts(IOUSBCompletionAction safeAction)
{
USBLog(1, "AppleUSBUHCI[%p]::PollInterrupts (unused)", this);
}
bool
AppleUSBUHCI::PrimaryInterruptFilter(OSObject *owner, IOFilterInterruptEventSource *source)
{
register AppleUSBUHCI *controller = (AppleUSBUHCI *)owner;
bool result = true;
if (!controller || controller->isInactive() || !controller->_uhciAvailable)
return false;
controller->_filterInterruptActive = true;
result = controller->FilterInterrupt();
controller->_filterInterruptActive = false;
return result;
}
void
AppleUSBUHCI::InterruptHandler(OSObject *owner, IOInterruptEventSource *source, int count)
{
AppleUSBUHCI *controller = (AppleUSBUHCI *)owner;
if (controller && !controller->isInactive() && controller->_uhciAvailable)
{
controller->HandleInterrupt();
}
}
bool
AppleUSBUHCI::FilterInterrupt(void)
{
UInt16 activeInterrupts;
AbsoluteTime timeStamp;
Boolean needSignal = false;
activeInterrupts = ioRead16(kUHCI_STS) & kUHCI_STS_INTR_MASK;
if (activeInterrupts != 0)
{
if (activeInterrupts & kUHCI_STS_HCPE)
{
_hostControllerProcessInterrupt = kUHCI_STS_HCPE;
ioWrite16(kUHCI_STS, kUHCI_STS_HCPE);
needSignal = true;
}
if (activeInterrupts & kUHCI_STS_HSE)
{
_hostSystemErrorInterrupt = kUHCI_STS_HSE;
ioWrite16(kUHCI_STS, kUHCI_STS_HSE);
needSignal = true;
}
if (activeInterrupts & kUHCI_STS_RD)
{
_resumeDetectInterrupt = kUHCI_STS_RD;
ioWrite16(kUHCI_STS, kUHCI_STS_RD);
needSignal = true;
}
if (activeInterrupts & kUHCI_STS_EI)
{
_usbErrorInterrupt = kUHCI_STS_EI;
ioWrite16(kUHCI_STS, kUHCI_STS_EI);
needSignal = true;
}
if (activeInterrupts & kUHCI_STS_INT)
{
clock_get_uptime(&timeStamp);
_usbCompletionInterrupt = kUHCI_STS_INT;
ioWrite16(kUHCI_STS, kUHCI_STS_INT);
needSignal = true;
if (!_inAbortIsochEP && (_outSlot < kUHCI_NVFRAMES))
{
AppleUHCIIsochTransferDescriptor *cachedHead;
UInt32 cachedProducer;
UInt16 curSlot, testSlot, nextSlot;
curSlot = (ReadFrameNumber() & kUHCI_NVFRAMES_MASK);
cachedHead = (AppleUHCIIsochTransferDescriptor*)_savedDoneQueueHead;
cachedProducer = _producerCount;
testSlot = _outSlot;
while (testSlot != curSlot)
{
IOUSBControllerListElement *thing, *nextThing;
AppleUHCIIsochTransferDescriptor *isochTD;
nextSlot = (testSlot+1) & kUHCI_NVFRAMES_MASK;
thing = _logicalFrameList[testSlot];
while (thing != NULL)
{
nextThing = thing->_logicalNext;
isochTD = OSDynamicCast(AppleUHCIIsochTransferDescriptor, thing);
if (!isochTD)
break;
_logicalFrameList[testSlot] = nextThing;
_frameList[testSlot] = HostToUSBLong(thing->GetPhysicalLink());
if (isochTD->_lowLatency)
isochTD->frStatus = isochTD->UpdateFrameList(timeStamp);
isochTD->_doneQueueLink = cachedHead;
cachedHead = isochTD;
cachedProducer++;
if (isochTD->_pEndpoint)
{
isochTD->_pEndpoint->onProducerQ++;
isochTD->_pEndpoint->scheduledTDs--;
}
thing = nextThing;
}
testSlot = nextSlot;
_outSlot = testSlot;
}
IOSimpleLockLock( _wdhLock );
_savedDoneQueueHead = cachedHead; _producerCount = cachedProducer;
IOSimpleLockUnlock( _wdhLock );
}
}
}
if (needSignal)
_interruptSource->signalInterrupt();
return false;
}
void
AppleUSBUHCI::HandleInterrupt(void)
{
UInt16 status;
UInt32 intrStatus;
bool needReset = false;
status = ioRead16(kUHCI_STS);
if (_hostControllerProcessInterrupt & kUHCI_STS_HCPE)
{
_hostControllerProcessInterrupt = 0;
USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller process error", this);
needReset = true;
}
if (_hostSystemErrorInterrupt & kUHCI_STS_HSE)
{
_hostSystemErrorInterrupt = 0;
USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller system error(CMD:%p STS:%p INTR:%p PORTSC1:%p PORTSC2:%p FRBASEADDR:%p ConfigCMD:%p)", this,(void*)ioRead16(kUHCI_CMD), (void*)ioRead16(kUHCI_STS), (void*)ioRead16(kUHCI_INTR), (void*)ioRead16(kUHCI_PORTSC1), (void*)ioRead16(kUHCI_PORTSC2), (void*)ioRead32(kUHCI_FRBASEADDR), (void*)_device->configRead16(kIOPCIConfigCommand));
needReset = true;
}
if (_resumeDetectInterrupt & kUHCI_STS_RD)
{
_resumeDetectInterrupt = 0;
USBLog(2, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller resume detected", this);
if (_uhciBusState == kUHCIBusStateSuspended)
{
ResumeController();
}
}
if (_usbErrorInterrupt & kUHCI_STS_EI)
{
_usbErrorInterrupt = 0;
USBLog(6, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller error interrupt", this);
}
if (_usbCompletionInterrupt & kUHCI_STS_INT)
{
_usbCompletionInterrupt = 0;
USBLog(7, "AppleUSBUHCI[%p]::HandleInterrupt - Normal interrupt", this);
if (_consumerCount != _producerCount)
{
USBLog(7, "AppleUSBUHCI[%p]::HandleInterrupt - Isoch was handled", this);
}
}
if (needReset)
{
IOSleep(1000);
USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Resetting controller due to errors detected at interrupt time (0x%x)", this, status);
Reset(true);
Run(true);
}
ProcessCompletedTransactions();
RHCheckStatus();
}