/** @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/module.h>
#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 <linux/version.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/sched.h>

#include <apci.h>
#include <apci3600.h>
#include <apci3600-kapi.h>

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
#include <linux/posix_types.h>
#include <linux/time.h>
#endif


//#include "../apci3600-private.h"

MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("ADDI-DATA GmbH <info@addi-data.com>");
MODULE_DESCRIPTION ("APCI-3600 IOCTL driver sample13");

#define SIZE_OF_INTERRUPT_FIFO 500
#define TIME_OUT 60


/*minor of the board*/
static int board_minor=0;

/*can be override*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)  
	MODULE_PARM (board_minor,"i");
	EXPORT_NO_SYMBOLS;
#else
	module_param(board_minor, int, S_IRUGO);
#endif
/**********************/
/* Struct declaration */
/**********************/
/*************************************************************/
/* Global structure which is called by the interrupt routine */
/*************************************************************/

typedef struct
{
	uint32_t   dw_NbrOfValues;
	uint32_t   dw_NbrOfComputerBuffer;
	uint32_t   pdw_ComputerBufferAddressKernelLevelArray[PCI3600_MAX_NBR_COMPUTER_BUFFER];
	uint32_t   pdw_ComputerBufferAddressApplicLevelArray[PCI3600_MAX_NBR_COMPUTER_BUFFER];
	uint32_t  dw_InterruptMask;
	uint32_t  dw_CompareInterrupt;
	uint8_t   b_FIFOErrorInterrupt;
	uint8_t   b_SDRAMOverFlowInterrupt;
	uint8_t   b_PCBufferOverFlowInterrupt;
	uint8_t   b_AutoStopInterrupt;
	uint32_t dw_InterruptIndex;
}
str_Sample13_InterruptFIFO;


typedef struct
{
	uint32_t  dw_ReceiveInterrupt;
	uint8_t    b_Error;
	str_Sample13_InterruptFIFO ps_InterruptFIFO [SIZE_OF_INTERRUPT_FIFO];
	uint32_t dw_ReadInterruptFIFOPointer;
	uint32_t dw_WriteInterruptFIFOPointer;
	uint8_t  b_InterruptFIFOFull;
	uint8_t  b_InterruptFIFOEmpty;
	uint8_t  b_InterruptFIFOOverFlow;
}
str_Sample13_UserStruct;


/*******************************/
/* Global variable declaration */
/*******************************/
static str_Sample13_UserStruct s_Sample13_GlobalUserStruct;
static str_Sample13_UserStruct *ps_Sample13_GlobalUserStructApp = &s_Sample13_GlobalUserStruct;

static uint32_t dw_Sample13_TransferNbr = 0;

//BEGIN BF151
static DECLARE_WAIT_QUEUE_HEAD(wait_interrupt);
//END BF151

/*Function Name : v_InterruptRoutine ()*/
/*+----------------------------------------------------------------------------+*/
/*| Function Name : v_InterruptRoutine ()                                      |*/
/*+----------------------------------------------------------------------------+*/
/*| Task :                                                                     |*/
/*  Initialise a board                                                          */
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters :                                                         |*/
/*                                                                              */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters :                                                        |*/
/*+----------------------------------------------------------------------------+*/
/*| Return Value :                                                             |*/
/*         > 0 : Warning                                                        */
/*         0 : No Error                                                         */
/*        < 0 : Error                                                           */
/*+----------------------------------------------------------------------------+*/
static void v_Sample13_InterruptRoutine  (struct pci_dev *pdev,
									 uint32_t   dw_InterruptSource,
									 uint32_t   dw_InterruptMask,
									 uint32_t   dw_NbrOfComputerBuffer,
									 uint32_t*   pdw_ComputerBufferAddressKernelLevelArray,
									 uint32_t*   pdw_ComputerBufferAddressApplicLevelArray)
{
	/*******************************/
	/* Local variable devlaration  */
	/*******************************/
	uint32_t* pdw_BufferPointer = NULL;
	uint32_t  dw_Cpt = 0;

	str_Sample13_UserStruct *ps_UserStruct;

	ps_UserStruct = ps_Sample13_GlobalUserStructApp;

	if (ps_UserStruct -> b_InterruptFIFOFull == 0 &&
			ps_UserStruct -> b_InterruptFIFOOverFlow == 0)
	{
		ps_UserStruct ->
		ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
		dw_InterruptMask = dw_InterruptMask;

		/**********************************/
		/* Test if Analog Input Interrupt */
		/**********************************/
		if (dw_InterruptSource & 0x3C) {
			/***********************************/
			/* Test if Compare Interrupt Occur */
			/***********************************/
			if (dw_InterruptMask & 1) {
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				dw_NbrOfComputerBuffer = dw_NbrOfComputerBuffer;
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				dw_NbrOfValues = 0;

				for (dw_Cpt = 0; dw_Cpt < dw_NbrOfComputerBuffer; dw_Cpt ++) {
					ps_UserStruct->
					ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
					pdw_ComputerBufferAddressKernelLevelArray[dw_Cpt] =  pdw_ComputerBufferAddressKernelLevelArray[dw_Cpt];

					ps_UserStruct->
					ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
					pdw_ComputerBufferAddressApplicLevelArray[dw_Cpt] =  pdw_ComputerBufferAddressApplicLevelArray[dw_Cpt];

					pdw_BufferPointer = (uint32_t *)(uintptr_t)pdw_ComputerBufferAddressKernelLevelArray[dw_Cpt];

					ps_UserStruct->
					ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
					dw_NbrOfValues = ps_UserStruct->
									 ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
									 dw_NbrOfValues + (pdw_BufferPointer[0] >> 4);

				}
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				dw_CompareInterrupt = 1;

			}
			/****************************/
			/* Test if FIFO Error Occur */
			/****************************/
			if (dw_InterruptMask & 2) {
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				b_FIFOErrorInterrupt = 1;

				ps_UserStruct->b_Error = 1;

			}
			/********************************/
			/* Test if SDRAM Overflow Occur */
			/********************************/
			if (dw_InterruptMask & 4) {
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				b_SDRAMOverFlowInterrupt = 1;

				ps_UserStruct->b_Error = 1;

			}
			/**********************************************/
			/* Test if PC Buffer Overflow Interrupt Occur */
			/**********************************************/
			if (dw_InterruptMask & 8) {
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				b_PCBufferOverFlowInterrupt = 1;

				ps_UserStruct->b_Error = 1;

			}
			/*************************************/
			/* Test if Auto-Stop Interrupt Occur */
			/*************************************/
			if (dw_InterruptMask & 0x10) {
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				dw_NbrOfComputerBuffer = dw_NbrOfComputerBuffer;
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				dw_NbrOfValues = 0;

				for (dw_Cpt = 0; dw_Cpt < dw_NbrOfComputerBuffer; dw_Cpt ++) {
					ps_UserStruct->
					ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
					pdw_ComputerBufferAddressKernelLevelArray[dw_Cpt] =  pdw_ComputerBufferAddressKernelLevelArray[dw_Cpt];

					ps_UserStruct->
					ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
					pdw_ComputerBufferAddressApplicLevelArray[dw_Cpt] =  pdw_ComputerBufferAddressApplicLevelArray[dw_Cpt];

					pdw_BufferPointer = (uint32_t *)(uintptr_t)pdw_ComputerBufferAddressKernelLevelArray[dw_Cpt];

					ps_UserStruct->
					ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
					dw_NbrOfValues = ps_UserStruct->
									 ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
									 dw_NbrOfValues + (pdw_BufferPointer[0] >> 4);

				}
				ps_UserStruct->
				ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
				b_AutoStopInterrupt = 1;

			}
		}
		ps_UserStruct->
		ps_InterruptFIFO[ps_UserStruct -> dw_WriteInterruptFIFOPointer].
		dw_InterruptIndex = ps_UserStruct->dw_ReceiveInterrupt + 1;

		ps_UserStruct -> dw_WriteInterruptFIFOPointer = (ps_UserStruct -> dw_WriteInterruptFIFOPointer + 1) % SIZE_OF_INTERRUPT_FIFO;
		ps_UserStruct -> b_InterruptFIFOEmpty = 0;
		//BEGIN BF151
		wake_up_interruptible(&wait_interrupt);
		//END BF15
		
		if (ps_UserStruct -> dw_WriteInterruptFIFOPointer == ps_UserStruct -> dw_ReadInterruptFIFOPointer) {
			ps_UserStruct -> b_InterruptFIFOFull = 1;

		}
		ps_UserStruct->dw_ReceiveInterrupt = ps_UserStruct->dw_ReceiveInterrupt + 1;

	} else
	{
		ps_UserStruct -> b_InterruptFIFOOverFlow = 1;

	}
}



/*Function Name : i_AnalogInBufferManagement()*/
/*+----------------------------------------------------------------------------+*/
/*| Function   Name   : i_AnalogInBufferManagement ()                       |*/
/*+----------------------------------------------------------------------------+*/
/*| Task              : Analog Input Buffer management                         |*/
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters  :                                                        |*/
/*                                                                              */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters : -                                                      |*/
/*+----------------------------------------------------------------------------+*/
/*| Return Value      :  0 : No error occur                                    |*/
/*|                     -1 : Error occur                                       |*/
/*+----------------------------------------------------------------------------+*/
static int i_AnalogInBufferManagement (struct pci_dev *pdev,
									 uint8_t  b_Module,
									 uint8_t  b_Mode)
{
	/************************/
	/* Variable declaration */
	/************************/
	//BEGIN BF151
	/*uint16_t                     w_Wait                             = 0;
	CHAR*                   pc_Wait                          = {"|/-\\"};*/
	//END BF151
	uint8_t                    b_Error                             = 0;
	
	int                      i_ReturnValue = 0;
	uint8_t                     b_TimeOut = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
	struct timespec64 time_Current;
	struct timespec64 time_Begin;
#else
	struct timeval time_Current;
	struct timeval time_Begin;
#endif


	memset (&time_Begin, 0, sizeof (time_Begin));
	memset (&time_Current, 0, sizeof (time_Current));

	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
		ktime_get_real_ts64(&time_Begin);
	#else
		do_gettimeofday (&time_Begin);
	#endif

	do
	{
		/**********************/
		/* Wait the interrupt */
		/**********************/
		printk("\n");
		printk ("\rWait interrupt\n");
		//BEGIN BF151
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
		if (! interruptible_sleep_on_timeout(&wait_interrupt,TIME_OUT*HZ)){
#else
            if (!wait_event_interruptible_timeout(wait_interrupt, 0, TIME_OUT * HZ)) {
#endif
			printk("TIME OUT\n");
			b_TimeOut = 1;
		}
// 		do_gettimeofday (&time_Current);
// 		if ( (time_Begin.tv_sec + 20) < time_Current.tv_sec )
// 			b_TimeOut = 1;

		//END BF151
	
// 		do {
// 			/*************************/
// 			/* Wait interrupt string */
// 			/*************************/
// 			if ((w_Wait % 8650) == 0) {
// 				printk ("\rWait interrupt %c", pc_Wait[w_Wait / 8650]);
// 
// 			}
// 			w_Wait = (w_Wait + 1) % 34600;
// 
// 			do_gettimeofday (&time_Current);
// 			if ( (time_Begin.tv_sec + TIME_OUT) < time_Current.tv_sec )
// 				b_TimeOut = 1;
// 
// 		} while ((ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOEmpty == 1) && (b_TimeOut == 0));

		while ((ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOEmpty == 0) &&
				(ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOOverFlow == 0) &&
				(ps_Sample13_GlobalUserStructApp -> b_Error == 0) &&
				(b_TimeOut == 0)) {

			printk("IRQ Cpt:%u IRQ Index:%u Comp:%u FIFO Error:%hu SDRAM Over:%hu PC Buffer Over:%hu Auto-Stop:%hu\n",
				   ps_Sample13_GlobalUserStructApp -> dw_ReceiveInterrupt,
				   ps_Sample13_GlobalUserStructApp ->
				   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
				   dw_InterruptIndex,
				   ps_Sample13_GlobalUserStructApp ->
				   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
				   dw_CompareInterrupt,
				   ps_Sample13_GlobalUserStructApp ->
				   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
				   b_FIFOErrorInterrupt,
				   ps_Sample13_GlobalUserStructApp ->
				   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
				   b_SDRAMOverFlowInterrupt,
				   ps_Sample13_GlobalUserStructApp ->
				   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
				   b_PCBufferOverFlowInterrupt,
				   ps_Sample13_GlobalUserStructApp ->
				   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
				   b_AutoStopInterrupt);

			/*************************/
			/* Test if DMA Interrupt */
			/*************************/
			if ((ps_Sample13_GlobalUserStructApp ->
					ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
					dw_CompareInterrupt == 1) ||
					(ps_Sample13_GlobalUserStructApp ->
					 ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
					 b_AutoStopInterrupt == 1)) {

				//                 /**********************/
				//                 /* Open the save file */
				//                 /**********************/
				//                 sprintf (s_Write, ".\\ANA_INP%d.bin", b_Module);
				//                 i_Handle = open (s_Write, O_CREAT |O_RDWR | O_BINARY | O_APPEND, S_IREAD | S_IWRITE);
				//
				//                 if (i_Handle != 0)
				//                    {
				//                    for (dw_BuffCpt = 0; dw_BuffCpt < ps_GlobalUserStructApp ->
				//                                                      ps_InterruptFIFO[ps_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
				//                                                      dw_NbrOfComputerBuffer; dw_BuffCpt ++)
				//                       {
				//                       pdw_BufferPointer = (uint32_t*)ps_GlobalUserStructApp ->
				//                                                   ps_InterruptFIFO[ps_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
				//                                                   pdw_ComputerBufferAddressApplicLevelArray[dw_BuffCpt];
				//
				//                       write (i_Handle,&(pdw_BufferPointer[1]),(pdw_BufferPointer [0] >> 4) * 4);
				//
				//                       }
				//                    dw_TransferNbr = dw_TransferNbr + 1;
				//
				//                    /*****************************************************/
				//                    /* Incr the read pointer of the Computer buffer */
				//                    /*****************************************************/
				//                    i_ReturnValue = i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer (dw_BoardHandle,
				//                                                                                                      ps_GlobalUserStructApp ->
				//                                                                                                      ps_InterruptFIFO[ps_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
				//                                                                                                      dw_NbrOfValues);
				//
				//                    if (i_ReturnValue == 0)
				//                       {
				//                       printf ("\ni_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer OK Nbr:%lu Transfer Nbr:%lu",ps_GlobalUserStructApp ->
				//                                                                                                                 ps_InterruptFIFO[ps_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
				//                                                                                                                 dw_NbrOfValues,dw_TransferNbr);
				//
				//                       }
				//                    else
				//                       {
				//                       v_DisplayError ("i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer",i_ReturnValue);
				//
				//                       }
				//                    /****************/
				//                    /*Close the file*/
				//                    /****************/
				//                    close (i_Handle);
				//
				//                    }

				dw_Sample13_TransferNbr = dw_Sample13_TransferNbr + 1;

				/*****************************************************/
				/* Incr the read pointer of the Computer buffer */
				/*****************************************************/
				i_ReturnValue = i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer (pdev,
								ps_Sample13_GlobalUserStructApp ->
								ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
								dw_NbrOfValues);

				if (i_ReturnValue == 0) {
					printk ("i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer OK Nbr:%u Transfer Nbr:%u\n",ps_Sample13_GlobalUserStructApp ->
							ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
							dw_NbrOfValues,dw_Sample13_TransferNbr);

				} else {
					printk ("i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer Error : %d\n",i_ReturnValue);

				}


			}
			ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer = (ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer + 1) % SIZE_OF_INTERRUPT_FIFO;
			ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOFull = 0;

			if (ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer == ps_Sample13_GlobalUserStructApp -> dw_WriteInterruptFIFOPointer) {
				ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOEmpty = 1;

			}
		}
		/************************************************/
		/* Test if there was an interrupt FIFO Overflow */
		/************************************************/
		if ((ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOOverFlow == 1) ||
				(ps_Sample13_GlobalUserStructApp -> b_Error == 1) ||
				(b_TimeOut == 1)) {
			if ((ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOOverFlow == 1) ||
					(b_TimeOut == 1)) {
				/*******************************/
				/* Stop the cyclic acquisition */
				/*******************************/
				i_ReturnValue = i_PCI3600_StopAnalogInModuleCyclicAcquisition (pdev,
								b_Module);

				if (i_ReturnValue == 0) {
					printk ("i_PCI3600_StopAnalogInModuleCyclicAcquisition OK\n");

				} else {
					printk ("i_PCI3600_StopAnalogInModuleCyclicAcquisition error : %d\n", i_ReturnValue);

				}
				printk("ERROR : Sample Interrupt FIFO Overflow  or time Out\n");
				b_Error = 1;

			} else {
				printk("ERROR : Board Error or PC Buffer overflow \n");
				b_Error = 1;

			}
			printk("Interrupt saved before the Error or Time Out...");

			/************************************************/
			/* Write the saved interrupt values in the file */
			/************************************************/
			do {
				printk("IRQ Cpt:%u IRQ Index:%u Comp:%u FIFO Error:%hu SDRAM Over:%hu PC Buffer Over:%hu Auto-Stop:%hu \n",
					   ps_Sample13_GlobalUserStructApp -> dw_ReceiveInterrupt,
					   ps_Sample13_GlobalUserStructApp ->
					   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
					   dw_InterruptIndex,
					   ps_Sample13_GlobalUserStructApp ->
					   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
					   dw_CompareInterrupt,
					   ps_Sample13_GlobalUserStructApp ->
					   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
					   b_FIFOErrorInterrupt,
					   ps_Sample13_GlobalUserStructApp ->
					   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
					   b_SDRAMOverFlowInterrupt,
					   ps_Sample13_GlobalUserStructApp ->
					   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
					   b_PCBufferOverFlowInterrupt,
					   ps_Sample13_GlobalUserStructApp ->
					   ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
					   b_AutoStopInterrupt);

				/*************************/
				/* Test if DMA Interrupt */
				/*************************/
				if ((ps_Sample13_GlobalUserStructApp ->
						ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
						dw_CompareInterrupt == 1) ||
						(ps_Sample13_GlobalUserStructApp ->
						 ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp ->dw_ReadInterruptFIFOPointer].
						 b_AutoStopInterrupt == 1)) {

					//                    /**********************/
					//                    /* Open the save file */
					//                    /**********************/
					//                    sprintf (s_Write, ".\\ANA_INP%d.bin", b_Module);
					//                    i_Handle = open (s_Write, O_CREAT |O_RDWR | O_BINARY | O_APPEND, S_IREAD | S_IWRITE);
					//
					//                    if (i_Handle != 0)
					//                       {
					//                       for (dw_BuffCpt = 0; dw_BuffCpt < ps_GlobalUserStructApp ->
					//                                                         ps_InterruptFIFO[ps_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
					//                                                         dw_NbrOfComputerBuffer; dw_BuffCpt ++)
					//                          {
					//                          pdw_BufferPointer = (uint32_t*)ps_GlobalUserStructApp ->
					//                                                      ps_InterruptFIFO[ps_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
					//                                                      pdw_ComputerBufferAddressApplicLevelArray[dw_BuffCpt];
					//
					//                          write (i_Handle,&(pdw_BufferPointer[1]),(pdw_BufferPointer [0] >> 4) * 4);
					//
					//                          }
					//                       dw_TransferNbr = dw_TransferNbr + 1;
					//
					//                       /*****************************************************/
					//                       /* Incr the read pointer of the Computer buffer */
					//                       /*****************************************************/
					//                       i_ReturnValue = i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer (dw_BoardHandle,
					//                                                                                                         ps_GlobalUserStructApp ->
					//                                                                                                         ps_InterruptFIFO[ps_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
					//                                                                                                         dw_NbrOfValues);
					//
					//                       if (i_ReturnValue == 0)
					//                          {
					//                          printf ("\nTransfer saved before the error: Nbr:%lu Transfer Nbr:%lu",ps_GlobalUserStructApp ->
					//                                                                                                                    ps_InterruptFIFO[ps_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
					//                                                                                                                    dw_NbrOfValues,dw_TransferNbr);
					//
					//                          }
					//                       else
					//                          {
					//                          v_DisplayError ("i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer",i_ReturnValue);
					//
					//                          }
					//                       /****************/
					//                       /*Close the file*/
					//                       /****************/
					//                       close (i_Handle);
					//
					//                       }

					dw_Sample13_TransferNbr = dw_Sample13_TransferNbr + 1;

					/*****************************************************/
					/* Incr the read pointer of the Computer buffer */
					/*****************************************************/
					i_ReturnValue = i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer (pdev,
									ps_Sample13_GlobalUserStructApp ->
									ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
									dw_NbrOfValues);

					if (i_ReturnValue == 0) {
						printk ("Transfer saved before the error: Nbr:%u Transfer Nbr:%u \n",ps_Sample13_GlobalUserStructApp ->
								ps_InterruptFIFO[ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer].
								dw_NbrOfValues,dw_Sample13_TransferNbr);

					} else {
						printk ("i_PCI3600_IncrAnalogInCyclicAcqBufferReadPointer Error : %d\n",i_ReturnValue);

					}
				}
				ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer = (ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer + 1) % SIZE_OF_INTERRUPT_FIFO;

				ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOFull = 0;

				if (ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer == ps_Sample13_GlobalUserStructApp -> dw_WriteInterruptFIFOPointer) {
					ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOEmpty = 1;

				}
			} while (ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOEmpty == 0);
		}
	} while ((b_Error == 0) && (b_TimeOut == 0));

	/********************/
	/* Error mamagement */
	/********************/
	/**************************/
	/* Test if no error occur */
	/**************************/
	if (b_Error == 0)
	{
		/******************/
		/* No error occur */
		/******************/
		return (0);

	} else
	{
		/***************/
		/* Error occur */
		/***************/
		return (-1);

	}
}

static int sample13 (struct pci_dev *pdev)
{// Reads 1 Analog Input in Auto-Stop/Ring Buffer Mode
	int i_ReturnValue = 0;
	uint8_t pb_EnableCurrentSource[2];
	uint8_t pb_Coupling[2];
	uint8_t pb_SingleDiffMode[2];
	uint8_t pb_Gain[2];
	uint32_t dw_OnBoardBufferSize = 0;
	uint32_t dw_CompareValue = 0;
	uint8_t b_Mode = 0;
	uint8_t b_Module = 0;

	pb_EnableCurrentSource[0] = 0;
	pb_EnableCurrentSource[1] = 0;

	pb_Coupling[0] = PCI3600_DC_COUPLING;
	pb_Coupling[1] = PCI3600_DC_COUPLING;

	pb_SingleDiffMode[0] = PCI3600_SINGLE_ENDED_MODE;
	pb_SingleDiffMode[1] = PCI3600_SINGLE_ENDED_MODE;

	pb_Gain[0] = 0;
	pb_Gain[1] = 0;


	printk("Reads 1 Analog Input in Auto-Stop/Ring Buffer Mode\n");
	/* Initialise the board */
	i_ReturnValue = i_PCI3600_InitBoard (pdev,
										 PCI3600_MASTER_MODE,
										 PCI3600_DIVISOR_4,
										 PCI3600_DIVISOR_4,
										 PCI3600_EXT_CLOCK_1,
										 PCI3600_EXT_CLOCK_1,
										 0,
										 0,
										 PCI3600_CHRONOMETER_DIVISOR_1);

	if (i_ReturnValue == 0)
	{
		printk ("i_PCI3600_InitBoard OK\n");

		i_ReturnValue = i_PCI3600_SetBoardIntKernelRoutine (pdev,v_Sample13_InterruptRoutine);

		if (i_ReturnValue == 0) {
			printk ("i_PCI3600_SetBoardIntKernelRoutine OK\n");

			ps_Sample13_GlobalUserStructApp -> dw_ReadInterruptFIFOPointer = 0;
			ps_Sample13_GlobalUserStructApp -> dw_WriteInterruptFIFOPointer = 0;
			ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOEmpty = 1;
			ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOFull = 0;
			ps_Sample13_GlobalUserStructApp -> b_InterruptFIFOOverFlow = 0;


			/**************************************/
			/* Initialise the analog input module */
			/**************************************/
			i_ReturnValue = i_PCI3600_InitAnalogInModule (pdev,
							0,
							pb_SingleDiffMode,
							pb_Coupling,
							pb_EnableCurrentSource,
							pb_Gain,
							PCI3600_SAMPLING_CLOCK1,
							PCI3600_SINGLE_SPEED);
			if (i_ReturnValue == 0) {
				printk ("i_PCI3600_InitAnalogInModule OK\n");



				/**************************************/
				/* Enter the on board RAM buffer size */
				/**************************************/
				//               Enter the nbr of bytes (n) of the on board RAM You want to use (1kB*2^n):");
				//               For example :");
				//               n = 0  ->    1 KB ->        256 Values
				//               n = 1  ->    2 KB ->        512 Values
				//               n = 2  ->    4 KB ->      1 024 Values
				//               n = 3  ->    8 KB ->      2 048 Values
				//               n = 4  ->   16 KB ->      4 096 Values
				//               n = 5  ->   32 KB ->      8 192 Values
				//               n = 6  ->   64 KB ->     16 384 Values
				//               n = 7  ->  128 KB ->     32 768 Values
				//               n = 8  ->  256 KB ->     65 536 Values
				//               n = 9  ->  512 KB ->    131 072 Values
				//               n = 10 ->    1 MB ->    262 144 Values
				//               n = 11 ->    2 MB ->    524 288 Values
				//               n = 12 ->    4 MB ->  1 048 576 Values
				//               n = 13 ->    8 MB ->  2 097 152 Values
				//               n = 14 ->   16 MB ->  4 194 304 Values
				//               n = 15 ->   32 MB ->  8 388 608 Values
				//               n = 16 ->   64 MB -> 16 777 216 Values
				//               n = 17 ->  128 MB -> 33 554 432 Values
				//               n = 18 ->  256 MB -> 67 108 864 Values

				dw_OnBoardBufferSize = 8;

				/***************************/
				/* Enter the compare value */
				/***************************/
				//               Enter the compare value (in nbr of value):
				dw_CompareValue =  8192;

				/*************************************/
				/* Enter the Cyclic acquisition mode */
				/*************************************/
				//                Enter the cyclic acquisition mode (0 : Auto-Stop, 1 : Ring buffer):

				b_Mode = 0;

				/******************************/
				/* Init the cylic acquisition */
				/******************************/
				i_ReturnValue = i_PCI3600_InitAnalogInModuleCyclicAcquisition (pdev,
								b_Module,
								b_Mode,
								dw_OnBoardBufferSize,
								dw_CompareValue);

				if (i_ReturnValue == 0) {
					printk ("i_PCI3600_InitAnalogInModuleCyclicAcquisition OK\n");


					/********************************/
					/* Start the cyclic acquisition */
					/********************************/
					i_ReturnValue = i_PCI3600_StartAnalogInModuleCyclicAcquisition (pdev,
									b_Module);

					if (i_ReturnValue == 0) {
						printk ("i_PCI3600_StartAnalogInModuleCyclicAcquisition OK\n");

						i_AnalogInBufferManagement (pdev,
													   b_Module,
													   b_Mode);

					} else {
						printk ("i_PCI3600_StartAnalogInModuleCyclicAcquisition Error : %d\n",i_ReturnValue);

					}

					i_ReturnValue = i_PCI3600_ReleaseAnalogInModuleCyclicAcquisition (pdev,
									b_Module);

					if (i_ReturnValue == 0) {
						printk ("i_PCI3600_ReleaseAnalogInModuleCyclicAcquisition OK\n");

					} else {
						printk ("i_PCI3600_ReleaseAnalogInModuleCyclicAcquisition Error : %d\n",i_ReturnValue);

					}
				} else {
					printk ("i_PCI3600_InitAnalogInModuleCyclicAcquisition Error : %d\n",i_ReturnValue);

				}


				/************************************/
				/* Release the analog input channel */
				/************************************/
				i_ReturnValue = i_PCI3600_ReleaseAnalogInModule (pdev, 0);

				if (i_ReturnValue == 0) {
					printk ("i_PCI3600_ReleaseAnalogInModule OK\n");
				} else {
					printk ("i_PCI3600_ReleaseAnalogInModule Error : %d\n",i_ReturnValue);
				}
			} else {
				printk ("i_PCI3600_InitAnalogInModule Error : %d\n",i_ReturnValue);
			}
		} else {
			printk("i_PCI3600_SetBoardIntKernelRoutine Error : %d\n",i_ReturnValue);
		}

	} else
	{
		printk ("i_PCI3600_InitBoard Error : %d\n",i_ReturnValue);

	}

	return (0);
}


//------------------------------------------------------------------------------
/** Called when module loads. */
static int __init
apci3600_sample13_init (void)
{

	printk("Using board minor %d (override with board_minor parameter)\n",board_minor);
	sample13(apci3600_lookup_board_by_index(board_minor));
	printk("Succesfull end of the sample, you can unload it...\n");

	return 0;

}

//-------------------------------------------------------------------
/** Called when module is unloaded. */
static void __exit
apci3600_sample13_exit (void)
{

	i_PCI3600_ResetBoardIntKernelRoutine(apci3600_lookup_board_by_index(board_minor));

}


//------------------------------------------------------------------------------
module_exit (apci3600_sample13_exit);

module_init (apci3600_sample13_init);

