/** @file interrupt.c
*
* @author Sylvain Nahas
*
* This module implements the interrupt related functions.
*/

/** @par LICENCE
* @verbatim
 Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code and the documentation.
        
        ADDI-DATA GmbH
        Dieselstrasse 3 
        D-77833 Ottersweier
        Tel: +19(0)7223/9493-0
        Fax: +49(0)7223/9493-92
        http://www.addi-data-com
        info@addi-data.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details. 
        
    You shoud find the complete GPL in the COPYING file accompanying 
    this source code. 
* @endverbatim
*/

#include "apci3001-private.h"

EXPORT_NO_SYMBOLS;

//------------------------------------------------------------------------------
/** has the card actually generated an interrupt ? 
 * 
 * @return 1 if the board has generated an interrupt, 0 otherwise
 * 
 * */
static __inline__ int HAS_INTERRUPTED(struct pci_dev * pdev )
{
	//FILLME
	return 0;
}
//------------------------------------------------------------------------------
/** acknowledge interrupt - 
 * 
 * @note This is board specific - usually setting a bit in a register
 */
static __inline__ void ACK_INTERRUPT(struct pci_dev * pdev)
{
	//FILLME
}

/** IRQ handler prototype has changed between 2.4 and 2.6.
 * in 2.4 the handler has not return value, in 2.6 it is of type irqreturn_t
 * IRQ_HANDLED means that the device did indeed need attention from the driver
 * IRQ_NONE means that the device didn't actually need attention
 * 
 * NOTE: the change between 2.4 and 2.6 was not so important that it needed 
 * two version of the function. BUT if in the course of the implementation you 
 * notice the changes are so important that maintaining a code for both version
 * in one function is just a hassle, DON'T HESITATE and create two versions
 * of the same function. 
 *
 */

//------------------------------------------------------------------------------
/** IRQ Handler */

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)	/* 2.4  */
	#define RETURN_HANDLED return
	#define RETURN_NONE return
#else
	#define RETURN_HANDLED return IRQ_HANDLED
	#define RETURN_NONE return IRQ_NONE
#endif


#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)	/* 2.4  */
	static void apci3001_do_interrupt(int irq, void * dev_id, struct pt_regs *regs)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)       /* 2.6.0 - 2.6.19  */
	static irqreturn_t apci3001_do_interrupt(int irq, void * dev_id, struct pt_regs *regs)
#else /* > 2.6.19 */
	static irqreturn_t apci3001_do_interrupt(int irq, void * dev_id)
#endif
{	
	/* board management */
	{
		unsigned long irqstate;
		APCI3001_LOCK(VOID_TO_PCIDEV(dev_id), &irqstate);
		{
			
			/* 1) is the interrupt generated by the card ? (remember, this is shared IRQ) */		
			if ( !HAS_INTERRUPTED(VOID_TO_PCIDEV(dev_id)) )
			{
				APCI3001_UNLOCK(VOID_TO_PCIDEV(dev_id), irqstate);
				RETURN_NONE;
			}

			{
				//FILLME
			}
	
			/* 5) acknowledge interrupt */
			ACK_INTERRUPT(VOID_TO_PCIDEV(dev_id));
	
		}
		APCI3001_UNLOCK(VOID_TO_PCIDEV(dev_id), irqstate);
	}
	/* Asynchronous IO signal implementation - send a SIGIO to all registered processes*/
	/* If using signal to inform user mode, uncomment following lines: */
	{
		/*
		if (APCI3001_PRIVDATA(VOID_TO_PCIDEV(dev_id))->async_queue)
		{		
			kill_fasync( &(APCI3001_PRIVDATA(VOID_TO_PCIDEV(dev_id))->async_queue), SIGIO, POLL_IN);
		}
		*/		
	}
	RETURN_HANDLED;
}

//------------------------------------------------------------------------------
int apci3001_register_interrupt(struct pci_dev * pdev)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
    if ( request_irq( pdev->irq, apci3001_do_interrupt, SA_SHIRQ, __DRIVER_NAME, pdev) )
#else
    if ( request_irq( pdev->irq, apci3001_do_interrupt, IRQF_SHARED, __DRIVER_NAME, pdev) )
#endif
	{
		printk(KERN_ERR "%s: can't register interrupt handler\n", __DRIVER_NAME );
		return -EBUSY;
	}
	
	/*board specific interruption initialisation*/
	{
		//FILLME
	}
	
	return 0;
}
//------------------------------------------------------------------------------
int apci3001_deregister_interrupt(struct pci_dev * pdev)
{
	free_irq( pdev->irq , pdev);
	return 0;
}



