InterruptControllerInterface.cpp 6.3 KB
//////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------//
//-- Copyright 2001 VAutomation Inc. Nashua NH USA. All rights reserved.//
//-- This software is provided under license and contains proprietary   //
//-- and confidential material which is the property of VAutomation Inc.//
//-- HTTP://www.vautomation.com											//
//----------------------------------------------------------------------//
//////////////////////////////////////////////////////////////////////////

// InterruptControllerInterface.cpp: implementation of the CInterruptControllerInterface class.
//
//////////////////////////////////////////////////////////////////////

#include "InterruptControllerInterface.h"
#include <stdio.h>
#include <stdlib.h>

/////////////////////////////////////////////////////////////////
// This is a simple implimentation with one function per IRQ
/////////////////////////////////////////////////////////////////

#define AUX_IRQ_LEV 0x200 // see pg 15 Tangent-A4 Ancillary Components Reference doc

struct IrqInfo
{
	InterruptCallbackType *m_callback;
	IRQNumberType		   m_irq_number;
	PriorityLevelType	   m_priority;
};

const int g_max_table_item_count = 20;

struct IrqLookupTable
{
	int m_table_item_count;
	IrqInfo m_callback_function_info[g_max_table_item_count];
};

/////////////////////////////////////////////////////////////////
// IRQ Functions
/////////////////////////////////////////////////////////////////
IrqLookupTable* g_internal_info_pointer = NULL;




void EnableIRQs()
{
#ifndef WIN32

	#define read_aux_reg(addr) _lr(addr)
	#define write_aux_reg(val,addr) _sr(val,addr)

	// 
	// set all interrupts to level 1 priority
	// 
	// priority level is set with AUX_IRQ_LEV aux reg (0x200). see pg 15
	// Tangent-A4 Ancillary Components Reference doc
	// 0 = priority level 1
	// 1 = priority level 2
	unsigned priority_levels = read_aux_reg(AUX_IRQ_LEV);


	// set interrupts 3-31 to priority level 1
	priority_levels &= 0x007; 

	write_aux_reg(priority_levels,AUX_IRQ_LEV);

	_enable();

#endif
}

void DisableIRQs()
{
#ifndef WIN32
	_disable();
#endif
}

CInterruptControllerInterface::CInterruptControllerInterface()
{
	m_internal_info_pointer = (void*)(new IrqLookupTable);
	if( g_internal_info_pointer != NULL )
	{
		printf("\nError: this implimentation only supports one instance of CInterruptControllerInterface.");
		return;
	}

	//Set all the callbacks to NULL
	for( int i=0; i<g_max_table_item_count; i++ )
	{
		((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[i].m_callback = NULL;
	}

	g_internal_info_pointer = (IrqLookupTable*)m_internal_info_pointer;
	((IrqLookupTable*)m_internal_info_pointer)->m_table_item_count = 0;

	EnableIRQs();	
}

CInterruptControllerInterface::~CInterruptControllerInterface()
{
	if( m_internal_info_pointer != NULL )
	{
		DisableIRQs();
		delete m_internal_info_pointer;
		g_internal_info_pointer = NULL;
	}
}

bool CInterruptControllerInterface::Create( char* device_name )
{
	//Really do need to do anything with device_name for most systems
	return(true);
}


bool CInterruptControllerInterface::AddIRQ( InterruptCallbackType *callback, IRQNumberType irq_number, PriorityLevelType priority)
{
	int index = 0;
	for( int i=0; i<g_max_table_item_count; i++ )
	{
		if( ((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[index].m_callback == NULL )
		{
			break;
		}
		index++;
	}

	if( index == ((IrqLookupTable*)m_internal_info_pointer)->m_table_item_count )
	{
		((IrqLookupTable*)m_internal_info_pointer)->m_table_item_count++;
	}

	if( ((IrqLookupTable*)m_internal_info_pointer)->m_table_item_count < g_max_table_item_count )
	{
		((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[index].m_callback = callback;
		((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[index].m_irq_number = irq_number;
		((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[index].m_priority = priority;
		return(true);
	}
	else
	{
		printf("Error: To many IRQ callback functions added max = %d\n", g_max_table_item_count );
		return( false );
	}

}

bool CInterruptControllerInterface::RemoveIRQ(  InterruptCallbackType *m_callback, IRQNumberType m_irq_number, PriorityLevelType m_priority)
{
	int index = 0;
	bool status = false;

	for( int i=0; i<((IrqLookupTable*)m_internal_info_pointer)->m_table_item_count; i++ )
	{
		if( ((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[index].m_callback == m_callback &&
			((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[index].m_irq_number == m_irq_number &&
			((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[index].m_priority == m_priority )
		
		{
			
			((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[index].m_callback = NULL;
			status = true;

			((IrqLookupTable*)m_internal_info_pointer)->m_table_item_count = 0;
			for( int j=0; j<g_max_table_item_count; j++ )
			{
				if(((IrqLookupTable*)m_internal_info_pointer)->m_callback_function_info[j].m_callback != NULL)
				{
					((IrqLookupTable*)m_internal_info_pointer)->m_table_item_count = j + 1;
				}
			}
			
			break;
		}
		index++;
	}

	return(status);
}


void CallFunctionsForIRQ( IRQNumberType irq_number )
{
	if( g_internal_info_pointer == NULL )
	{
		//May happen at startup and if the controller was never allocated.
		return;
	}
	int items = g_internal_info_pointer->m_table_item_count;

	for( int i=0; i<items; i++ )
	{
		if( g_internal_info_pointer->m_callback_function_info[i].m_irq_number == irq_number )
		{
			(g_internal_info_pointer->m_callback_function_info[i].m_callback)();
		}
	}
}

#ifdef WIN32  //Just so this will compile without hcarc
	#define _Interrupt1 
#endif 

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

_Interrupt1 void handler_0(void) 
{
	CallFunctionsForIRQ(IRQ_0);
}

_Interrupt1 void handler_1(void) 
{
	CallFunctionsForIRQ(IRQ_1);
}

_Interrupt1 void handler_2(void) 
{
	CallFunctionsForIRQ(IRQ_2);
}

_Interrupt1 void handler_3(void) 
{
	CallFunctionsForIRQ(IRQ_3);
}

_Interrupt1 void handler_4(void) 
{
	CallFunctionsForIRQ(IRQ_4);
}

_Interrupt1 void handler_5(void) 
{
	CallFunctionsForIRQ(IRQ_5);
}

_Interrupt1 void handler_6(void) 
{
	CallFunctionsForIRQ(IRQ_6);
}

_Interrupt1 void handler_7(void) 
{
	CallFunctionsForIRQ(IRQ_7);
}

#ifdef __cplusplus
}
#endif