IOInterruptEventSource.cpp [plain text]
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOInterrupts.h>
#include <IOKit/IOTimeStamp.h>
#include <IOKit/IOWorkLoop.h>
#if KDEBUG
#define IOTimeTypeStampS(t) \
do { \
IOTimeStampStart(IODBG_INTES(t), \
(uintptr_t) this, (uintptr_t) owner); \
} while(0)
#define IOTimeTypeStampE(t) \
do { \
IOTimeStampEnd(IODBG_INTES(t), \
(uintptr_t) this, (uintptr_t) owner); \
} while(0)
#define IOTimeStampLatency() \
do { \
IOTimeStampEnd(IODBG_INTES(IOINTES_LAT), \
(uintptr_t) this, (uintptr_t) owner); \
} while(0)
#else
#define IOTimeTypeStampS(t)
#define IOTimeTypeStampE(t)
#define IOTimeStampLatency()
#endif
#define super IOEventSource
OSDefineMetaClassAndStructors(IOInterruptEventSource, IOEventSource)
OSMetaClassDefineReservedUnused(IOInterruptEventSource, 0);
OSMetaClassDefineReservedUnused(IOInterruptEventSource, 1);
OSMetaClassDefineReservedUnused(IOInterruptEventSource, 2);
OSMetaClassDefineReservedUnused(IOInterruptEventSource, 3);
OSMetaClassDefineReservedUnused(IOInterruptEventSource, 4);
OSMetaClassDefineReservedUnused(IOInterruptEventSource, 5);
OSMetaClassDefineReservedUnused(IOInterruptEventSource, 6);
OSMetaClassDefineReservedUnused(IOInterruptEventSource, 7);
bool IOInterruptEventSource::init(OSObject *inOwner,
Action inAction,
IOService *inProvider,
int inIntIndex)
{
bool res = true;
if ( !super::init(inOwner, (IOEventSourceAction) inAction) )
return false;
provider = inProvider;
producerCount = consumerCount = 0;
autoDisable = explicitDisable = false;
intIndex = -1;
if (inProvider) {
int intType;
res = (kIOReturnSuccess
== inProvider->getInterruptType(inIntIndex, &intType));
if (res) {
IOInterruptAction intHandler;
autoDisable = (intType == kIOInterruptTypeLevel);
if (autoDisable) {
intHandler = OSMemberFunctionCast(IOInterruptAction,
this, &IOInterruptEventSource::disableInterruptOccurred);
}
else
intHandler = OSMemberFunctionCast(IOInterruptAction,
this, &IOInterruptEventSource::normalInterruptOccurred);
res = (kIOReturnSuccess == inProvider->registerInterrupt
(inIntIndex, this, intHandler));
if (res)
intIndex = inIntIndex;
}
}
return res;
}
IOInterruptEventSource *
IOInterruptEventSource::interruptEventSource(OSObject *inOwner,
Action inAction,
IOService *inProvider,
int inIntIndex)
{
IOInterruptEventSource *me = new IOInterruptEventSource;
if (me && !me->init(inOwner, inAction, inProvider, inIntIndex)) {
me->release();
return 0;
}
return me;
}
void IOInterruptEventSource::free()
{
if (provider && intIndex != -1)
provider->unregisterInterrupt(intIndex);
super::free();
}
void IOInterruptEventSource::enable()
{
if (provider && intIndex != -1) {
provider->enableInterrupt(intIndex);
explicitDisable = false;
enabled = true;
}
}
void IOInterruptEventSource::disable()
{
if (provider && intIndex != -1) {
provider->disableInterrupt(intIndex);
explicitDisable = true;
enabled = false;
}
}
const IOService *IOInterruptEventSource::getProvider() const
{
return provider;
}
int IOInterruptEventSource::getIntIndex() const
{
return intIndex;
}
bool IOInterruptEventSource::getAutoDisable() const
{
return autoDisable;
}
bool IOInterruptEventSource::checkForWork()
{
unsigned int cacheProdCount = producerCount;
int numInts = cacheProdCount - consumerCount;
IOInterruptEventAction intAction = (IOInterruptEventAction) action;
if (numInts > 0) {
IOTimeStampLatency();
IOTimeTypeStampS(IOINTES_CLIENT);
IOTimeStampConstant(IODBG_INTES(IOINTES_ACTION),
(uintptr_t) intAction, (uintptr_t) owner);
(*intAction)(owner, this, numInts);
IOTimeTypeStampE(IOINTES_CLIENT);
consumerCount = cacheProdCount;
if (autoDisable && !explicitDisable)
enable();
}
else if (numInts < 0) {
IOTimeStampLatency();
IOTimeTypeStampS(IOINTES_CLIENT);
IOTimeStampConstant(IODBG_INTES(IOINTES_ACTION),
(uintptr_t) intAction, (uintptr_t) owner);
(*intAction)(owner, this, -numInts);
IOTimeTypeStampE(IOINTES_CLIENT);
consumerCount = cacheProdCount;
if (autoDisable && !explicitDisable)
enable();
}
return false;
}
void IOInterruptEventSource::normalInterruptOccurred
(void *, IOService *, int )
{
IOTimeTypeStampS(IOINTES_INTCTXT);
IOTimeStampLatency();
producerCount++;
IOTimeTypeStampS(IOINTES_SEMA);
signalWorkAvailable();
IOTimeTypeStampE(IOINTES_SEMA);
IOTimeTypeStampE(IOINTES_INTCTXT);
}
void IOInterruptEventSource::disableInterruptOccurred
(void *, IOService *prov, int source)
{
IOTimeTypeStampS(IOINTES_INTCTXT);
IOTimeStampLatency();
prov->disableInterrupt(source);
producerCount++;
IOTimeTypeStampS(IOINTES_SEMA);
signalWorkAvailable();
IOTimeTypeStampE(IOINTES_SEMA);
IOTimeTypeStampE(IOINTES_INTCTXT);
}
void IOInterruptEventSource::interruptOccurred
(void *refcon, IOService *prov, int source)
{
if (autoDisable && prov)
disableInterruptOccurred(refcon, prov, source);
else
normalInterruptOccurred(refcon, prov, source);
}