/** @file apcie1564_ksample_counter.c
*
* @author Sylvain Nahas
*
* Sample to demonstrate the use of the functions:
* 
* - APCIE1564_CounterInitAndStart
* - APCIE1564_CounterReset
* - APCIE1564_SetInterruptCallback
* - APCIE1564_ClearInterruptCallback
* 
*/

/** @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 <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
	#include <linux/config.h>
#else
	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
		#include <linux/autoconf.h>
	#else
		#include <generated/autoconf.h>
	#endif
#endif

#include <apcie1564-kapi.h>
#include "apcie1564-private.h"


MODULE_LICENSE("GPL");
MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>");
MODULE_DESCRIPTION("Sample APCIE1564 counter");

EXPORT_NO_SYMBOLS;

//------------------------------------------------------------------------------

/* This sample manages only one board: the first discovered in the system. */
static struct pci_dev * apcie1564_ksc_0 = NULL;

//------------------------------------------------------------------------------
/** This is the user interrupt. it outputs the event */
static void apcie1564_ksc_user_interrupt(struct pci_dev *pdev, apcie1564_event_t* evt)
{
	switch(evt->source)
	{
		case APCIE1564_EVT_FROM_DIGITAL_INPUT:
			printk("apcie1564 %s: digin inter. from input %lu\n",pci_name(pdev),evt->param1);
			break;
		case APCIE1564_EVT_FROM_COUNTER:
			printk("apcie1564 %s: counter interrupt from counter %lu\n",pci_name(pdev),evt->param1);
			break;
		default:
			printk("apcie1564 %s: unknown event: source: %u\n",pci_name(pdev),evt->source);
	}
}

//------------------------------------------------------------------------------
static int ksample_init(struct pci_dev * pdev)
{
	/* register interrupt handler */
	if ( APCIE1564_SetInterruptCallback(pdev, apcie1564_ksc_user_interrupt) )
	{
		printk(KERN_WARNING "apcie1564_ksc: could not register user interrupt callback\n");
		return -ENODEV;
	}
	
	/* configure all three counters with reload value 20, direction down, level 1 */
	
	if ( APCIE1564_CounterInitAndStart(pdev,0,20,0,1) )
	{
		APCIE1564_ClearInterruptCallback(pdev);
		return -ENODEV;
	}
	
	if ( APCIE1564_CounterInitAndStart(pdev,1,20,0,1) )
	{
		APCIE1564_CounterStop(pdev,0);
		APCIE1564_ClearInterruptCallback(pdev);
		return -ENODEV;
	}
	
	if ( APCIE1564_CounterInitAndStart(pdev,2,20,0,1) )
	{
		APCIE1564_CounterStop(pdev,0);
		APCIE1564_CounterStop(pdev,1);
		APCIE1564_ClearInterruptCallback(pdev);
		return -ENODEV;
	}
	return 0;	
}

//------------------------------------------------------------------------------
/** Called when module loads. 
 *  Present boards have already be detected and initialised by the APCI 1564 driver 
 */
static int __init apcie1564_ksc_init(void)
{
	/* search the first APCI564 present - */
	apcie1564_ksc_0 = apcie1564_lookup_board_by_index(0);
	
	if (!apcie1564_ksc_0)
	{
		printk(KERN_WARNING "apcie1564_ksc: no APCI 1564 found");
		return -ENODEV;
	}
	
	/* a board has been found. */
	printk("apcie1564_ksc: found board %s\n",pci_name(apcie1564_ksc_0));
	
	/* let start the sample */
	{
		int ret;
		unsigned long irqstate;
		/* get exclusive access to the board (local interruptions are deactivated) */
		APCIE1564_lock(apcie1564_ksc_0,&irqstate);
		{
			ret = ksample_init(apcie1564_ksc_0);
		}
		APCIE1564_unlock(apcie1564_ksc_0,irqstate);
	
		/* done - user should generate some interrupts */	
		return ret;
	}
}
//-------------------------------------------------------------------
/** Called when module is unloaded. */
static void __exit apcie1564_ksc_exit(void)
{
	unsigned long irqstate;
	/* get exclusive access to the board (local interruptions are deactivated) */
	APCIE1564_lock(apcie1564_ksc_0,&irqstate);
	{
		/* stop all counter */
		APCIE1564_CounterStop(apcie1564_ksc_0,0);
		APCIE1564_CounterStop(apcie1564_ksc_0,1);
		APCIE1564_CounterStop(apcie1564_ksc_0,2);
		
		/* deregister interrupt callback */
		APCIE1564_ClearInterruptCallback(apcie1564_ksc_0);
	} 
	APCIE1564_unlock(apcie1564_ksc_0,irqstate);
}
//------------------------------------------------------------------------------
module_exit(apcie1564_ksc_exit);
module_init(apcie1564_ksc_init);

