#include <architecture/i386/pio.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOPlatformExpert.h>
#include "AppleIntelClassicPIC.h"
#define kIntelReservedIntVectors 0x40
extern OSSymbol * gIntelPICName;
#undef super
#define super IOInterruptController
OSDefineMetaClassAndStructors(AppleIntelClassicPIC, IOInterruptController);
bool AppleIntelClassicPIC::start(IOService * provider)
{
IOInterruptAction handler;
if ( super::start(provider) == false ) return false;
vectors = (IOInterruptVector *) IOMalloc( kNumVectors *
sizeof(IOInterruptVector) );
if ( vectors == NULL ) return false;
bzero(vectors, kNumVectors * sizeof(IOInterruptVector));
for ( int cnt = 0; cnt < kNumVectors; cnt++ )
{
vectors[cnt].interruptLock = IOLockAlloc();
if ( vectors[cnt].interruptLock == NULL )
{
return false;
}
}
maskInterrupts = 0xffff & ~(1 << kPICSlaveID);
initializePIC( kPIC1BasePort,
kPIC_ICW1_IC4,
kIntelReservedIntVectors,
(1 << kPICSlaveID),
kPIC_ICW4_uPM );
outb( kPIC_OCW1(kPIC1BasePort), maskInterrupts & 0xff );
outb( kPIC_OCW3(kPIC1BasePort), kPIC_OCW3_MBO | kPIC_OCW3_RR );
outb( kPIC_OCW2(kPIC1BasePort), kPIC_OCW2_R |
kPIC_OCW2_SL |
kPIC_OCW2_LEVEL(2) );
initializePIC( kPIC2BasePort,
kPIC_ICW1_IC4,
kIntelReservedIntVectors + 8,
kPICSlaveID,
kPIC_ICW4_uPM );
outb( kPIC_OCW1(kPIC2BasePort), maskInterrupts >> 8 );
outb( kPIC_OCW3(kPIC2BasePort), kPIC_OCW3_MBO | kPIC_OCW3_RR );
triggerTypes = inb( kPIC1TriggerTypePort ) |
( inb( kPIC2TriggerTypePort ) << 8 );
getPlatform()->setCPUInterruptProperties(provider);
handler = getInterruptHandlerAddress();
if ( provider->registerInterrupt(0, this, handler, 0) != kIOReturnSuccess )
panic("AppleIntelClassicPIC: Failed to install platform interrupt handler");
provider->enableInterrupt(0);
getPlatform()->registerInterruptController(gIntelPICName, this);
return true;
}
void AppleIntelClassicPIC::free(void)
{
if ( vectors )
{
for ( int cnt = 0; cnt < kNumVectors; cnt++ )
{
if (vectors[cnt].interruptLock)
IOLockFree(vectors[cnt].interruptLock);
}
IOFree( vectors, kNumVectors * sizeof(IOInterruptVector) );
vectors = 0;
}
super::free();
}
void AppleIntelClassicPIC::initializePIC( UInt16 port,
UInt8 icw1, UInt8 icw2,
UInt8 icw3, UInt8 icw4 )
{
outb( kPIC_ICW1(port), kPIC_ICW1_MBO | icw1 );
outb( kPIC_ICW2(port), icw2 );
outb( kPIC_ICW3(port), icw3 );
outb( kPIC_ICW4(port), icw4 );
}
int AppleIntelClassicPIC::getVectorType(long vectorNumber,
IOInterruptVector * vector)
{
return getTriggerType(vectorNumber);
}
IOInterruptAction AppleIntelClassicPIC::getInterruptHandlerAddress(void)
{
return (IOInterruptAction) &AppleIntelClassicPIC::handleInterrupt;
}
IOReturn AppleIntelClassicPIC::handleInterrupt(void * savedState,
IOService * nub,
int source)
{
IOInterruptVector * vector;
long vectorNumber;
typedef void (*IntelClockFuncType)(void *);
IntelClockFuncType clockFunc;
vectorNumber = source - kIntelReservedIntVectors;
if (vectorNumber >= kNumVectors)
return kIOReturnSuccess;
disableInterrupt(vectorNumber);
ackInterrupt( vectorNumber);
vector = &vectors[vectorNumber];
vector->interruptActive = 1;
if ( !vector->interruptDisabledSoft )
{
if ( vector->interruptRegistered )
{
if (vectorNumber == kClockIRQ) {
clockFunc = (IntelClockFuncType) vector->handler;
clockFunc(savedState);
}
else
{
vector->handler(vector->target, vector->refCon,
vector->nub, vector->source);
}
if ( vector->interruptDisabledSoft )
{
vector->interruptDisabledHard = 1;
}
else
{
enableInterrupt(vectorNumber);
}
}
}
else
{
vector->interruptDisabledHard = 1;
}
vector->interruptActive = 0;
return kIOReturnSuccess;
}
bool AppleIntelClassicPIC::vectorCanBeShared(long vectorNumber,
IOInterruptVector * vector)
{
if ( getVectorType(vectorNumber, vector) == kIOInterruptTypeLevel )
return true;
else
return false;
}
void AppleIntelClassicPIC::initVector(long vectorNumber,
IOInterruptVector * vector)
{
super::initVector(vectorNumber, vector);
}
void AppleIntelClassicPIC::disableVectorHard(long vectorNumber,
IOInterruptVector * vector)
{
if (vectorNumber == kPICSlaveID) return;
disableInterrupt(vectorNumber);
}
void AppleIntelClassicPIC::enableVector(long vectorNumber,
IOInterruptVector * vector)
{
enableInterrupt(vectorNumber);
}