/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Syborg interrupt control and dispatch
*
*/

#include <syborg_priv.h>

SInterruptHandler SyborgInterrupt::Handlers[KNumSyborgInts];

void SyborgInterrupt::DisableAndClearAll()
{
  WriteReg(KHwBaseSic, 3, 0);
}

void SyborgInterrupt::Init1()
{
	__KTRACE_OPT(KBOOT,Kern::Printf("SyborgInterrupt::Init1()"));

	for(TUint i = 0; i < KNumSyborgInts; i++)
	{
		Handlers[i].iPtr = (TAny*)i;
		Handlers[i].iIsr = Spurious;
	}

	DisableAndClearAll();
	
	Arm::SetIrqHandler((TLinAddr)SyborgInterrupt::IrqDispatch);
	Arm::SetFiqHandler((TLinAddr)SyborgInterrupt::FiqDispatch);
}

void SyborgInterrupt::Init3()
{
	__KTRACE_OPT(KHARDWARE,Kern::Printf("SyborgInterrupt::Init3()"));
}

void SyborgInterrupt::Spurious(TAny* anId)
{
	// Handle an unexpected interrupt
	Kern::Fault("SpuriousInt", (TInt)anId);
}

EXPORT_C TInt Interrupt::Bind(TInt anId, TIsr anIsr, TAny* aPtr)
{
  __KTRACE_OPT(KHARDWARE,Kern::Printf("Interrupt::Bind(anId=%d anIsr=0x%X aPtr=0x%X)",anId,anIsr,aPtr));
	if((anId >= 0) && ((TUint)anId < KNumSyborgInts))
	{
		SInterruptHandler& h = SyborgInterrupt::Handlers[anId];
		TInt irq = NKern::DisableAllInterrupts();
        TInt r;
		if(h.iIsr != SyborgInterrupt::Spurious)
		{
            r = KErrInUse;
	    }
		else
		{
    	    h.iPtr = aPtr;
	    	h.iIsr = anIsr;
            r = KErrNone;
		}
		NKern::RestoreInterrupts(irq);
		return r;
	}
	return KErrArgument;
}

EXPORT_C TInt Interrupt::Unbind(TInt anId)
{
	__KTRACE_OPT(KHARDWARE,Kern::Printf("Interrupt::Unbind(%d)",anId));
	if((anId >= 0) && ((TUint)anId < KNumSyborgInts))
	{
		SInterruptHandler& h = SyborgInterrupt::Handlers[anId];
		TInt irq = NKern::DisableAllInterrupts();
    	TInt r;
		if(h.iIsr == SyborgInterrupt::Spurious)
		{
			r = KErrGeneral;
		}
		else
		{
            // Reset pointer to handler back to default
			h.iPtr = (TAny*)anId;
			h.iIsr = SyborgInterrupt::Spurious;	
			// Disable the interrupt
			TSyborg::DisableInt(anId);
			r = KErrNone;
        }
		NKern::RestoreInterrupts(irq);
    	return r;
	}
	return KErrArgument;
}

EXPORT_C TInt Interrupt::Enable(TInt anId)
{
	__KTRACE_OPT(KHARDWARE,Kern::Printf("Interrupt::Enable(%d)",anId));
	if((anId >= 0) && ((TUint)anId < KNumSyborgInts))
	{
		if(SyborgInterrupt::Handlers[anId].iIsr == SyborgInterrupt::Spurious)
		{
	        return KErrNotReady;
		}
		else
		{
		  TSyborg::EnableInt(anId);
		  return KErrNone;
		}
	}
	return KErrArgument;
}

EXPORT_C TInt Interrupt::Disable(TInt anId)
{
	__KTRACE_OPT(KHARDWARE,Kern::Printf("Interrupt::Disable(%d)",anId));
	if((anId >= 0) && ((TUint)anId < KNumSyborgInts))
	{
	  TSyborg::DisableInt(anId);
	  return KErrNone;
	}
	return KErrArgument;
}

EXPORT_C TInt Interrupt::Clear(TInt anId)
{
	__KTRACE_OPT(KHARDWARE,Kern::Printf("Interrupt::Clear(%d)",anId));
	if((anId >= 0) && ((TUint)anId < KNumSyborgInts))
	{
        return KErrNone;
	}
	return KErrArgument;
}

EXPORT_C TInt Interrupt::SetPriority(TInt anId, TInt aPriority)
{
	__KTRACE_OPT(KHARDWARE,Kern::Printf("Interrupt::SetPriority(anId=%d aPriority=0x%X)",anId,aPriority));
	return KErrNotSupported;
}

