
/*+-----------------------------------------------------------------------+  */
/*| (C) ADDI-DATA GmbH Dieselstra?e 3 D-77833 Ottersweier                 |  */
/*+-----------------------------------------------------------------------+  */
/*| Tel : +49 (0) 7223/9493-0     | email : info@addi-data.com            |  */
/*| Fax : +49 (0) 7223/9493-92    | Internet : http:$/$/www.addi-data.com   |*/
/*+-------------------------------+---------------------------------------+  */
/*| Project : APCI-3600           | Compiler : Microsoft Visual C++       |  */
/*| Module name : Global_Intern.C |  Version : 6.0                        |  */
/*+-------------------------------+---------------------------------------+  */
/*| Author : Guinot Catherine       Date : 27/09/2004                     |  */
/*+-----------------------------------------------------------------------+  */
/*| Description : Global Inter Functions of the APCI-3600                 |  */
/*+-----------------------------------------------------------------------+  */
/*|                             UPDATES                                   |  */
/*+----------+-----------+------------------------------------------------+  */
/*| Date     | Author    | Description of updates                         |  */
/*+----------+-----------+------------------------------------------------+  */
/*|          |           |                                                |  */
/*+----------+-----------+------------------------------------------------+  */
#include "apci3600-private.h"

#ifdef INTERN_DEBUG
#define INTERN_DPRINTK(fmt, args...)	printk("%s: " fmt, __FUNCTION__ , ## args)
#define INTERN_MARK	printk( "%s: %s:%i\n",__FILE__, __FUNCTION__ , __LINE__)
#else
#define INTERN_DPRINTK(fmt, args...)
#define INTERN_MARK
#endif

/*i_PCI3600_Intern_ReserveOnBoardRAMBuffer*/
/*+----------------------------------------------------------------------------+*/
/*| Function Name : i_PCI3600_Intern_ReserveOnBoardRAMBuffer ()                |*/
/*+----------------------------------------------------------------------------+*/
/*| Task :                                                                     |*/
/*  Reserve a part of the on board RAM                                          */
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters :                                                         |*/
/*  pstr_PCI3600_SingleBoardInformation ps_SingleBoard : Board information      */
/*  uint8_t b_RessourceID : ID of the resource who want to reserve RAM Buffer      */
/*  uint32_t dw_BufferSize : Size in Byte                                          */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters :                                                        |*/
/*                                                                              */
/*+----------------------------------------------------------------------------+*/
/*| Return Value :                                                             |*/
/*         > 0 : Warning                                                        */
/*         0 : No Error                                                         */
/*+----------------------------------------------------------------------------+*/
int __needlock i_PCI3600_Intern_ReserveOnBoardRAMBuffer (pstr_PCI3600_SingleBoardInformation ps_SingleBoard,
		uint8_t b_RessourceID,
		uint32_t dw_BufferSize) // Size in Bytes
{
	int i_ReturnValue = 0;
	uint8_t b_Cpt = 0;
	uint8_t b_Found = 0;
	uint8_t b_SaveIndexFreeBuffer = 0;
	uint32_t dw_SizeDiff = ps_SingleBoard ->
						s_HardwareInformations.
						dw_OnBoardRAMSize;

	INTERN_MARK;

	/***********************************************/
	/* Free the reserved buffer for this ressource */
	/***********************************************/
	i_PCI3600_Intern_FreeOnBoardRAMBuffer (ps_SingleBoard, b_RessourceID);

	/*********************************/
	/* Search the best buffer to use */
	/*********************************/
	for (b_Cpt = 0;b_Cpt < ps_SingleBoard -> b_NbrOfFreeBuffer;b_Cpt ++)
	{
		if (ps_SingleBoard ->
				ps_OnBoardRAMFreeBuffer [b_Cpt].
				dw_BufferSize >= dw_BufferSize) {
			if ((ps_SingleBoard ->
					ps_OnBoardRAMFreeBuffer [b_Cpt].
					dw_BufferSize - dw_BufferSize) <= dw_SizeDiff) {
				b_SaveIndexFreeBuffer = b_Cpt;
				dw_SizeDiff = ps_SingleBoard ->
							  ps_OnBoardRAMFreeBuffer [b_Cpt].
							  dw_BufferSize - dw_BufferSize;
				b_Found = 1;

			}
			if (dw_SizeDiff == 0) {
				/**************/
				/* do a break */
				/**************/
				b_Cpt = ps_SingleBoard -> b_NbrOfFreeBuffer;

			}
		}
	}
	/**************************/
	/* Test if found a buffer */
	/**************************/
	if (b_Found == 1)
	{
		/*************************************/
		/* Save the parameters of the buffer */
		/*************************************/
		ps_SingleBoard ->
		ps_OnBoardRAMReservedBuffer [b_RessourceID].
		dw_BufferSize = dw_BufferSize;

		ps_SingleBoard ->
		ps_OnBoardRAMReservedBuffer [b_RessourceID].
		dw_Address = ps_SingleBoard ->
					 ps_OnBoardRAMFreeBuffer [b_SaveIndexFreeBuffer].
					 dw_Address;

		ps_SingleBoard ->
		ps_OnBoardRAMReservedBuffer [b_RessourceID].
		b_Init = 1;

		/*******************************/
		/* Update the free buffer list */
		/*******************************/
		if (ps_SingleBoard ->
				ps_OnBoardRAMReservedBuffer [b_RessourceID].
				dw_BufferSize == ps_SingleBoard ->
				ps_OnBoardRAMFreeBuffer [b_SaveIndexFreeBuffer].
				dw_BufferSize) {
			if (ps_SingleBoard -> b_NbrOfFreeBuffer > 1) {
				for (b_Cpt = b_SaveIndexFreeBuffer; b_Cpt < (ps_SingleBoard -> b_NbrOfFreeBuffer - 1); b_Cpt ++) {
					memcpy (&(ps_SingleBoard ->
							  ps_OnBoardRAMFreeBuffer [b_Cpt]),&(ps_SingleBoard ->
																 ps_OnBoardRAMFreeBuffer [b_Cpt + 1]),
							sizeof(ps_SingleBoard ->
								   ps_OnBoardRAMFreeBuffer [b_Cpt]));

				}
				ps_SingleBoard -> b_NbrOfFreeBuffer = ps_SingleBoard -> b_NbrOfFreeBuffer - 1;

			} else {
				ps_SingleBoard -> b_NbrOfFreeBuffer = 0;

			}
		} else {
			ps_SingleBoard ->
			ps_OnBoardRAMFreeBuffer [b_SaveIndexFreeBuffer].
			dw_BufferSize = ps_SingleBoard ->
							ps_OnBoardRAMFreeBuffer [b_SaveIndexFreeBuffer].
							dw_BufferSize - ps_SingleBoard ->
							ps_OnBoardRAMReservedBuffer [b_RessourceID].
							dw_BufferSize;

			ps_SingleBoard ->
			ps_OnBoardRAMFreeBuffer [b_SaveIndexFreeBuffer].
			dw_Address = ps_SingleBoard ->
						 ps_OnBoardRAMFreeBuffer [b_SaveIndexFreeBuffer].
						 dw_Address + ps_SingleBoard ->
						 ps_OnBoardRAMReservedBuffer [b_RessourceID].
						 dw_BufferSize;

		}
	} else
	{
		i_ReturnValue = -1;

	}
	return (i_ReturnValue);

}
/*i_PCI3600_Intern_FreeOnBoardRAMBuffer*/
/*+----------------------------------------------------------------------------+*/
/*| Function Name : i_PCI3600_Intern_FreeOnBoardRAMBuffer ()                   |*/
/*+----------------------------------------------------------------------------+*/
/*| Task :                                                                     |*/
/*  Free a part of the on board RAM                                             */
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters :                                                         |*/
/*  pstr_PCI3600_SingleBoardInformation ps_SingleBoard : Board information      */
/*  uint8_t b_RessourceID : ID of the resource who want to free RAM Buffer         */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters :                                                        |*/
/*                                                                              */
/*+----------------------------------------------------------------------------+*/
/*| Return Value :                                                             |*/
/*         > 0 : Warning                                                        */
/*         0 : No Error                                                         */
/*+----------------------------------------------------------------------------+*/
int __needlock i_PCI3600_Intern_FreeOnBoardRAMBuffer (pstr_PCI3600_SingleBoardInformation ps_SingleBoard,
		uint8_t b_RessourceID)
{
	int i_ReturnValue = 0;
	uint8_t b_Cpt = 0;
	uint8_t b_Found = 0;

	INTERN_MARK;

	/*************************************************/
	/* Test if this index has already reserve memory */
	/*************************************************/
	if (ps_SingleBoard ->
			ps_OnBoardRAMReservedBuffer [b_RessourceID].
			b_Init == 1) {
		ps_SingleBoard ->
		ps_OnBoardRAMReservedBuffer [b_RessourceID].
		b_Init = 0;

		/**************************/
		/* Update the buffer list */
		/**************************/
		for (b_Cpt = 0; b_Cpt < ps_SingleBoard -> b_NbrOfFreeBuffer;b_Cpt ++) {
			if ((ps_SingleBoard ->
					ps_OnBoardRAMFreeBuffer [b_Cpt].
					dw_Address + ps_SingleBoard ->
					ps_OnBoardRAMFreeBuffer [b_Cpt].
					dw_BufferSize + 4) == ps_SingleBoard ->
					ps_OnBoardRAMReservedBuffer [b_RessourceID].
					dw_Address) {
				ps_SingleBoard ->
				ps_OnBoardRAMFreeBuffer [b_Cpt].
				dw_BufferSize = ps_SingleBoard ->
								ps_OnBoardRAMFreeBuffer [b_Cpt].
								dw_BufferSize + ps_SingleBoard ->
								ps_OnBoardRAMReservedBuffer [b_RessourceID].
								dw_BufferSize;

				b_Found = 1;

				b_Cpt = ps_SingleBoard -> b_NbrOfFreeBuffer;

			} else {
				if ((ps_SingleBoard ->
						ps_OnBoardRAMReservedBuffer [b_RessourceID].
						dw_Address + ps_SingleBoard ->
						ps_OnBoardRAMReservedBuffer [b_RessourceID].
						dw_BufferSize + 4) == ps_SingleBoard ->
						ps_OnBoardRAMFreeBuffer [b_Cpt].
						dw_Address) {
					ps_SingleBoard ->
					ps_OnBoardRAMFreeBuffer [b_Cpt].
					dw_BufferSize = ps_SingleBoard ->
									ps_OnBoardRAMFreeBuffer [b_Cpt].
									dw_BufferSize + ps_SingleBoard ->
									ps_OnBoardRAMReservedBuffer [b_RessourceID].
									dw_BufferSize;

					ps_SingleBoard ->
					ps_OnBoardRAMFreeBuffer [b_Cpt].
					dw_Address = ps_SingleBoard ->
								 ps_OnBoardRAMReservedBuffer [b_RessourceID].
								 dw_Address;

					b_Found = 1;

					b_Cpt = ps_SingleBoard -> b_NbrOfFreeBuffer;

				}
			}
		}
		if (b_Found == 0) {
			/**********************************************/
			/* Add this buffer to the list of free buffer */
			/**********************************************/
			ps_SingleBoard ->
			ps_OnBoardRAMFreeBuffer [ps_SingleBoard -> b_NbrOfFreeBuffer].
			dw_Address = ps_SingleBoard ->
						 ps_OnBoardRAMReservedBuffer [b_RessourceID].
						 dw_Address;

			ps_SingleBoard ->
			ps_OnBoardRAMFreeBuffer [ps_SingleBoard -> b_NbrOfFreeBuffer].
			dw_BufferSize = ps_SingleBoard ->
							ps_OnBoardRAMReservedBuffer [b_RessourceID].
							dw_BufferSize;

			ps_SingleBoard -> b_NbrOfFreeBuffer = ps_SingleBoard -> b_NbrOfFreeBuffer + 1;

		}
	}
	return (i_ReturnValue);

}
/*i_PCI3600_Intern_PCI9054_CompleteScatterGatherDescriptor*/
/*+----------------------------------------------------------------------------+*/
/*| Function Name : i_PCI3600_Intern_PCI9054_CompleteScatterGatherDescriptor ()|*/
/*+----------------------------------------------------------------------------+*/
/*| Task :                                                                     |*/
/*  Complete the descriptor List for the DMA transfer                           */
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters :                                                         |*/
/*  uint8_t b_TransferDirection : Define the direction of the transfer            */
/*  uint8_t b_InterruptFlag     : Define if the Interrupt is used or not          */
/*  uint8_t b_ReserveHeaderPlace : Define if a uint32_t must be Reserved in the PC   */
/*                               Buffer at the beginning of the buffer          */
/*  uint32_t dw_PCBufferPhysicalAddress : Physical Address of the PC buffer       */
/*  uint32_t dw_PCBufferSize : Size of the PC Buffer                              */
/*  uint32_t dw_PCBufferReadPointer : Read Pointer of the PC Buffer               */
/*  uint32_t dw_PCBufferWritePointer : Write Pointer of the PC Buffer             */
/*  uint32_t dw_PCBufferNbrOfData    : Nbr of Data already present in the PC      */
/*                                   buffer                                     */
/*  uint32_t dw_OnBoardBufferAddress : Physical Address of the On board RAM       */
/*                                   Buffer                                     */
/*  uint32_t dw_OnBoardBufferSize    : Size of the on board RAM Buffer            */
/*  uint32_t dw_OnBoardBufferReadPointer : Read Pointer of the On Board RAM       */
/*                                       Buffer                                 */
/*  uint32_t dw_OnBoardBufferWritePointer : Write Pointer of the on board RAM     */
/*                                        buffer                                */
/*  uint32_t dw_OnBoardBufferNbrOfData : Nbr of data already in the on board RAM  */
/*                                     buffer                                   */
/*  uint32_t dw_NbrOfDescriptorAllocated : Nbr of Descriptor allocated            */
/*  uint32_t dw_DescriptorListPhysicalAddress : Physical Address of the first     */
/*                                            descriptor                        */
/*  pstr_PCI9054DMADescriptor ps_PCI9054DMADescriptor : Pointer of the          */
/*                                                      descriptor list         */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters :                                                        |*/
/*  uint32_t* pdw_NbrOfDescriptorUsed : Nbr of descriptor used                    */
/*  uint32_t* pdw_NbrOfDataTransferedByTheDescriptor : Nbr of Data transfered by  */
/*                                                   all descriptors            */
/*+----------------------------------------------------------------------------+*/
/*| Return Value :                                                             |*/
/*         > 0 : Warning                                                        */
/*         0 : No Error                                                         */
/*+----------------------------------------------------------------------------+*/
int __needlock i_PCI3600_Intern_PCI9054_CompleteScatterGatherDescriptor (uint8_t b_TransferDirection,
		uint8_t b_InterruptFlag,
		uint8_t b_ReserveHeaderPlace,
		uint32_t dw_PCBufferPhysicalAddress,
		uint32_t dw_PCBufferSize, // In Byte
		uint32_t dw_PCBufferReadPointer, // In uint32_t
		uint32_t dw_PCBufferWritePointer, // In uint32_t
		uint32_t dw_PCBufferNbrOfData, // In uint32_t
		uint32_t dw_OnBoardBufferAddress,
		uint32_t dw_OnBoardBufferSize, // In Byte
		uint32_t dw_OnBoardBufferReadPointer, // In uint32_t
		uint32_t dw_OnBoardBufferWritePointer, // In uint32_t
		uint32_t dw_OnBoardBufferNbrOfData, // In uint32_t
		uint32_t dw_NbrOfDescriptorAllocated,
		uint32_t dw_DescriptorListPhysicalAddress,
		pstr_PCI9054DMADescriptor ps_PCI9054DMADescriptor,
		uint32_t* pdw_NbrOfDescriptorUsed,
		uint32_t* pdw_NbrOfDataTransferedByTheDescriptor)

// Notice :
//          For b_TransferDirection == PCI3600_DMA_BOARD_TO_PC :
//          This function is only called when the PC Buffer is not full
//          The case with only 1 uint32_t free in the PC buffer is defined as PC Buffer full
{
	int i_ReturnValue = 0;
	//        uint32_t dw_DescriptorCpt = 0;
	uint32_t dw_NbrOfDataForTheDescriptor = 0;
	uint32_t dw_NbrOfDataWhoCanBeWriteOnTheOnBoardBuffer = 0;
	uint32_t dw_NbrOfDataWhoCanBeWriteOnThePCBuffer = 0;
	uint32_t dw_TempNbrOfPCData = 0;
	uint32_t dw_TempNbrOfOnBoardData = 0;
	uint8_t  b_PCBufferBreaked = 0;

#ifdef DEBUG_
	printk ("dw_PCBufferPhysicalAddress %x\n", dw_PCBufferPhysicalAddress);
	printk ("dw_PCBufferSize %u\n", dw_PCBufferSize);
	printk ("dw_PCBufferReadPointer %x\n", dw_PCBufferReadPointer);
	printk ("dw_PCBufferWritePointer %x\n", dw_PCBufferWritePointer);
	printk ("dw_PCBufferNbrOfData %u\n", dw_PCBufferNbrOfData);
	printk ("dw_OnBoardBufferAddress %x\n", dw_OnBoardBufferAddress);
	printk ("dw_OnBoardBufferSize %u\n", dw_OnBoardBufferSize);
	printk ("dw_OnBoardBufferReadPointer %x\n", dw_OnBoardBufferReadPointer);
	printk ("dw_OnBoardBufferWritePointer %x\n", dw_OnBoardBufferWritePointer);
	printk ("dw_OnBoardBufferNbrOfData %u\n", dw_OnBoardBufferNbrOfData);
	printk ("dw_NbrOfDescriptorAllocated %u\n", dw_NbrOfDescriptorAllocated);
	printk ("dw_DescriptorListPhysicalAddress %x\n", dw_DescriptorListPhysicalAddress);
	printk ("ps_PCI9054DMADescriptor %p\n", ps_PCI9054DMADescriptor);
	printk ("ps_PCI9054DMADescriptor[0] %p\n", ps_PCI9054DMADescriptor[0]);
#endif

	INTERN_MARK;

	/*******************************/
	/* Test the transfer direction */
	/*******************************/
	if (b_TransferDirection == PCI3600_DMA_PC_TO_BOARD)
	{
		dw_NbrOfDataWhoCanBeWriteOnTheOnBoardBuffer = (dw_OnBoardBufferSize / 4) - dw_OnBoardBufferNbrOfData;

		/*********************************/
		/* Test the number of descriptor */
		/*********************************/
		if (// CG 23/02/05 : Test the nbr of descriptor allocated
			//*pdw_NbrOfDescriptorUsed < PCI3600_MAX_NUMBER_OF_DESCRIPTOR
			*pdw_NbrOfDescriptorUsed < dw_NbrOfDescriptorAllocated) {
			/************************************************************/
			/* Define the number of data to tranfer for this descriptor */
			/************************************************************/
			/**************************************************/
			/* Test if the rest of the PC buffer is not break */
			/**************************************************/
			if ((dw_PCBufferReadPointer + dw_PCBufferNbrOfData) <= (dw_PCBufferSize / 4)) {
				/***********************************************************/
				/* Test if the size of the on board buffer is great enough */
				/***********************************************************/
				if (dw_NbrOfDataWhoCanBeWriteOnTheOnBoardBuffer >= dw_PCBufferNbrOfData) {
					/********************************************************/
					/* Test if the rest of the on board buffer is not break */
					/********************************************************/
					if ((dw_OnBoardBufferWritePointer + dw_PCBufferNbrOfData) <= (dw_OnBoardBufferSize / 4)) {
						dw_NbrOfDataForTheDescriptor = dw_PCBufferNbrOfData;

					} else {
						dw_NbrOfDataForTheDescriptor = (dw_OnBoardBufferSize / 4) - dw_OnBoardBufferWritePointer;

					}
				} else {
					/********************************************************/
					/* Test if the rest of the on board buffer is not break */
					/********************************************************/
					if ((dw_OnBoardBufferWritePointer + dw_NbrOfDataWhoCanBeWriteOnTheOnBoardBuffer) <= (dw_OnBoardBufferSize / 4)) {
						dw_NbrOfDataForTheDescriptor = dw_NbrOfDataWhoCanBeWriteOnTheOnBoardBuffer;

					} else {
						dw_NbrOfDataForTheDescriptor = (dw_OnBoardBufferSize / 4) - dw_OnBoardBufferWritePointer;

					}
				}
			} else {
				/************************************************************/
				/* Calculate the nbr of data to transfer from the PC Buffer */
				/************************************************************/
				dw_TempNbrOfPCData = (dw_PCBufferSize / 4)-dw_PCBufferReadPointer;

				/***********************************************************/
				/* Test if the size of the on board buffer is great enough */
				/***********************************************************/
				if (dw_NbrOfDataWhoCanBeWriteOnTheOnBoardBuffer >= dw_TempNbrOfPCData) {
					/********************************************************/
					/* Test if the rest of the on board buffer is not break */
					/********************************************************/
					if ((dw_OnBoardBufferWritePointer + dw_TempNbrOfPCData ) <= (dw_OnBoardBufferSize / 4)) {
						dw_NbrOfDataForTheDescriptor = dw_TempNbrOfPCData;

					} else {
						dw_NbrOfDataForTheDescriptor = (dw_OnBoardBufferSize / 4) - dw_OnBoardBufferWritePointer;

					}
				} else {
					/********************************************************/
					/* Test if the rest of the on board buffer is not break */
					/********************************************************/
					if ((dw_OnBoardBufferWritePointer + dw_NbrOfDataWhoCanBeWriteOnTheOnBoardBuffer) <= (dw_OnBoardBufferSize / 4)) {
						dw_NbrOfDataForTheDescriptor = dw_NbrOfDataWhoCanBeWriteOnTheOnBoardBuffer;

					} else {
						dw_NbrOfDataForTheDescriptor = (dw_OnBoardBufferSize / 4) - dw_OnBoardBufferWritePointer;

					}
				}
			}
			/*************************************************************/
			/* Test if the size of the transfer is greater than 8 MBytes */
			/*************************************************************/
			if ((dw_NbrOfDataForTheDescriptor * 4) > (8388608UL - 4)) {
				/*************************************/
				/* Set the transfer size to 8 MBytes */
				/*************************************/
				dw_NbrOfDataForTheDescriptor = (8388608UL - 4) / 4;

			}
			/***********************************/
			/* Save the descriptor information */
			/***********************************/
			ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
			dw_BufferPhysicalAddress = dw_PCBufferPhysicalAddress + (dw_PCBufferReadPointer * 4);

			ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
			dw_LocalBusPhysicalAddress = dw_OnBoardBufferAddress + (dw_OnBoardBufferWritePointer * 4);

			ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
			dw_BufferSize = (dw_NbrOfDataForTheDescriptor * 4);


			ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
			dw_NextDescriptorAddress = (dw_DescriptorListPhysicalAddress +
										(sizeof(str_PCI9054DMADescriptor) * (*pdw_NbrOfDescriptorUsed + 1))) |
									   1;

			/*************************************************************/
			/* Incr the number of data transfered by the descriptor */
			/*************************************************************/
			*pdw_NbrOfDataTransferedByTheDescriptor = *pdw_NbrOfDataTransferedByTheDescriptor +
					(ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
					 dw_BufferSize / 4);

			/*******************************************/
			/* Incr the number of descriptor used */
			/*******************************************/
			*pdw_NbrOfDescriptorUsed = *pdw_NbrOfDescriptorUsed + 1;

			/*********************************************/
			/* Test if there is already Data to transfer */
			/*********************************************/
			if (((((dw_OnBoardBufferSize / 4)- dw_OnBoardBufferNbrOfData) - dw_NbrOfDataForTheDescriptor) > 0) &&
					((dw_PCBufferNbrOfData - dw_NbrOfDataForTheDescriptor) > 0)) {
				i_PCI3600_Intern_PCI9054_CompleteScatterGatherDescriptor (b_TransferDirection,
						b_InterruptFlag,
						0,
						dw_PCBufferPhysicalAddress,
						dw_PCBufferSize,
						(dw_PCBufferReadPointer + dw_NbrOfDataForTheDescriptor) % (dw_PCBufferSize / 4),
						dw_PCBufferWritePointer,
						dw_PCBufferNbrOfData - dw_NbrOfDataForTheDescriptor,
						dw_OnBoardBufferAddress,
						dw_OnBoardBufferSize,
						dw_OnBoardBufferReadPointer,
						(dw_OnBoardBufferWritePointer + dw_NbrOfDataForTheDescriptor) % (dw_OnBoardBufferSize / 4),
						dw_OnBoardBufferNbrOfData + dw_NbrOfDataForTheDescriptor,
						dw_NbrOfDescriptorAllocated,
						dw_DescriptorListPhysicalAddress,
						ps_PCI9054DMADescriptor,
						pdw_NbrOfDescriptorUsed,
						pdw_NbrOfDataTransferedByTheDescriptor);

			} else {
				if (*pdw_NbrOfDescriptorUsed > 0) {
					/***************************/
					/* Test the interrupt Flag */
					/***************************/
					if (b_InterruptFlag == 1) {
						/*********************************************************/
						/* Set the end of chain bit and the interrupt enable bit */
						/*********************************************************/
						ps_PCI9054DMADescriptor[(*pdw_NbrOfDescriptorUsed) - 1].
						dw_NextDescriptorAddress = 4 | 2 | 1;

					} else {
						/****************************/
						/* Set the end of chain bit */
						/****************************/
						ps_PCI9054DMADescriptor[(*pdw_NbrOfDescriptorUsed) - 1].
						dw_NextDescriptorAddress =  2 | 1;

					}
				}
			}
		}
	} else
	{
		/**************************************************/
		/* Test if a uint32_t must be reserved for the header*/
		/**************************************************/
		if (b_ReserveHeaderPlace == 1) {
			dw_NbrOfDataWhoCanBeWriteOnThePCBuffer = ((dw_PCBufferSize / 4) - dw_PCBufferNbrOfData) - 1;

		} else {
			dw_NbrOfDataWhoCanBeWriteOnThePCBuffer = (dw_PCBufferSize / 4) - dw_PCBufferNbrOfData;

		}
		/********************************/
		/* Test if End of the PC buffer */
		/********************************/
		if ((((dw_PCBufferWritePointer + 1) < (dw_PCBufferSize / 4)) && (b_ReserveHeaderPlace == 1)) ||
				(b_ReserveHeaderPlace == 0)) {
			if (b_ReserveHeaderPlace == 1) {
				dw_PCBufferWritePointer = (dw_PCBufferWritePointer + 1) % (dw_PCBufferSize / 4);

			}
			/*********************************/
			/* Test the number of descriptor */
			/*********************************/
			if (// CG 23/02/05 : Test the nbr of descriptor allocated
				//*pdw_NbrOfDescriptorUsed < PCI3600_MAX_NUMBER_OF_DESCRIPTOR
				*pdw_NbrOfDescriptorUsed < dw_NbrOfDescriptorAllocated) {
				/************************************************************/
				/* Define the number of data to tranfer for this descriptor */
				/************************************************************/
				/********************************************************/
				/* Test if the rest of the on board buffer is not break */
				/********************************************************/
				if ((dw_OnBoardBufferReadPointer + dw_OnBoardBufferNbrOfData) <= (dw_OnBoardBufferSize / 4)) {
					/*****************************************************/
					/* Test if the size of the PC buffer is great enough */
					/*****************************************************/
					if (dw_NbrOfDataWhoCanBeWriteOnThePCBuffer >= dw_OnBoardBufferNbrOfData) {
						/**************************************************/
						/* Test if the rest of the PC buffer is not break */
						/**************************************************/
						if ((dw_PCBufferWritePointer + dw_OnBoardBufferNbrOfData ) <= (dw_PCBufferSize / 4)) {
							dw_NbrOfDataForTheDescriptor = dw_OnBoardBufferNbrOfData;

						} else {
							dw_NbrOfDataForTheDescriptor = (dw_PCBufferSize / 4) - dw_PCBufferWritePointer;

							b_PCBufferBreaked = 1;

						}
					} else {
						/**************************************************/
						/* Test if the rest of the PC buffer is not break */
						/**************************************************/
						if ((dw_PCBufferWritePointer + dw_NbrOfDataWhoCanBeWriteOnThePCBuffer) <= (dw_PCBufferSize / 4)) {
							dw_NbrOfDataForTheDescriptor = dw_NbrOfDataWhoCanBeWriteOnThePCBuffer;

						} else {
							dw_NbrOfDataForTheDescriptor = (dw_PCBufferSize / 4) - dw_PCBufferWritePointer;

							b_PCBufferBreaked = 1;

						}
					}
				} else {
					/******************************************************************/
					/* Calculate the nbr of data to transfer from the On board Buffer */
					/******************************************************************/
					dw_TempNbrOfOnBoardData = (dw_OnBoardBufferSize / 4)-dw_OnBoardBufferReadPointer;

					/*****************************************************/
					/* Test if the size of the PC buffer is great enough */
					/*****************************************************/
					if (dw_NbrOfDataWhoCanBeWriteOnThePCBuffer >= dw_TempNbrOfOnBoardData) {
						/**************************************************/
						/* Test if the rest of the PC buffer is not break */
						/**************************************************/
						if ((dw_PCBufferWritePointer + dw_TempNbrOfOnBoardData) <= (dw_PCBufferSize / 4)) {
							dw_NbrOfDataForTheDescriptor = dw_TempNbrOfOnBoardData;

						} else {
							dw_NbrOfDataForTheDescriptor = (dw_PCBufferSize / 4) - dw_PCBufferWritePointer;

							b_PCBufferBreaked = 1;

						}
					} else {
						/**************************************************/
						/* Test if the rest of the PC buffer is not break */
						/**************************************************/
						if ((dw_PCBufferWritePointer + dw_NbrOfDataWhoCanBeWriteOnThePCBuffer) <= (dw_PCBufferSize / 4)) {
							dw_NbrOfDataForTheDescriptor = dw_NbrOfDataWhoCanBeWriteOnThePCBuffer;

						} else {
							dw_NbrOfDataForTheDescriptor = (dw_PCBufferSize / 4) - dw_PCBufferWritePointer;

							b_PCBufferBreaked = 1;

						}
					}
				}
				/*************************************************************/
				/* Test if the size of the transfer is greater than 8 MBytes */
				/*************************************************************/
				if ((dw_NbrOfDataForTheDescriptor * 4) > (8388608UL - 4)) {
					/*************************************/
					/* Set the transfer size to 8 MBytes */
					/*************************************/
					dw_NbrOfDataForTheDescriptor = (8388608UL - 4) / 4;

				}
				/***********************************/
				/* Save the descriptor information */
				/***********************************/
				ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
				dw_BufferPhysicalAddress = dw_PCBufferPhysicalAddress + (dw_PCBufferWritePointer * 4);

				ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
				dw_LocalBusPhysicalAddress = dw_OnBoardBufferAddress + (dw_OnBoardBufferReadPointer * 4);

				ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
				dw_BufferSize = (dw_NbrOfDataForTheDescriptor * 4);

				ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
				dw_NextDescriptorAddress = (dw_DescriptorListPhysicalAddress +
											(sizeof(str_PCI9054DMADescriptor) * (*pdw_NbrOfDescriptorUsed + 1))) | 8 | 1;

#ifdef DEBUG_
				printk ("*pdw_NbrOfDescriptorUsed %u\n", *pdw_NbrOfDescriptorUsed);
				printk ("\tdw_BufferPhysicalAddress %x\n", ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].dw_BufferPhysicalAddress);
				printk ("\tdw_LocalBusPhysicalAddress %x\n", ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].dw_LocalBusPhysicalAddress);
				printk ("\tdw_BufferSize %u\n", ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].dw_BufferSize);
				printk ("\tps_PCI9054DMADescriptor[%i] %x\n", *pdw_NbrOfDescriptorUsed, &(ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed]));
				printk ("\tps_PCI9054DMADescriptor[%i].dw_NextDescriptorAddress %p\n", *pdw_NbrOfDescriptorUsed, ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].dw_NextDescriptorAddress);
#endif
				/*************************************************************/
				/* Incr the number of data transfered by the descriptor */
				/*************************************************************/
				*pdw_NbrOfDataTransferedByTheDescriptor = *pdw_NbrOfDataTransferedByTheDescriptor +
						(ps_PCI9054DMADescriptor[*pdw_NbrOfDescriptorUsed].
						 dw_BufferSize / 4);

				/*******************************************/
				/* Incr the number of descriptor used */
				/*******************************************/
				*pdw_NbrOfDescriptorUsed = *pdw_NbrOfDescriptorUsed + 1;

				/*********************************************/
				/* Test if there is already Data to transfer */
				/*********************************************/
				if (// CG 23/02/05 : Warning Header is not always present !
					//((((dw_PCBufferSize / 4)- dw_PCBufferNbrOfData) - (dw_NbrOfDataForTheDescriptor + 1)) > 0) &&
					//((dw_OnBoardBufferNbrOfData - dw_NbrOfDataForTheDescriptor) > 0)
					((((dw_PCBufferSize / 4)- dw_PCBufferNbrOfData) - (dw_NbrOfDataForTheDescriptor + b_ReserveHeaderPlace)) > 0) &&
					((dw_OnBoardBufferNbrOfData - dw_NbrOfDataForTheDescriptor) > 0)) {
					i_PCI3600_Intern_PCI9054_CompleteScatterGatherDescriptor (b_TransferDirection,
							b_InterruptFlag,
							b_PCBufferBreaked,
							dw_PCBufferPhysicalAddress,
							dw_PCBufferSize,
							dw_PCBufferReadPointer,
							(dw_PCBufferWritePointer + dw_NbrOfDataForTheDescriptor) % (dw_PCBufferSize / 4),
							// Begin CG 23/02/05 : Don't forget the header
							// dw_PCBufferNbrOfData + dw_NbrOfDataForTheDescriptor,
							dw_PCBufferNbrOfData + dw_NbrOfDataForTheDescriptor + b_ReserveHeaderPlace,
							// End CG 23/02/05 : Don't forget the header
							dw_OnBoardBufferAddress,
							dw_OnBoardBufferSize,
							(dw_OnBoardBufferReadPointer + dw_NbrOfDataForTheDescriptor) % (dw_OnBoardBufferSize / 4),
							dw_OnBoardBufferWritePointer,
							dw_OnBoardBufferNbrOfData - dw_NbrOfDataForTheDescriptor,
							dw_NbrOfDescriptorAllocated,
							dw_DescriptorListPhysicalAddress,
							ps_PCI9054DMADescriptor,
							pdw_NbrOfDescriptorUsed,
							pdw_NbrOfDataTransferedByTheDescriptor);

				} else {
					if (*pdw_NbrOfDescriptorUsed > 0) {
						/***************************/
						/* Test the interrupt Flag */
						/***************************/
						if (b_InterruptFlag == 1) {
							/*********************************************************/
							/* Set the end of chain bit and the interrupt enable bit */
							/*********************************************************/
							ps_PCI9054DMADescriptor[(*pdw_NbrOfDescriptorUsed) - 1].
							dw_NextDescriptorAddress = 8 | 4 | 2 | 1;
							
						} else {
							/****************************/
							/* Set the end of chain bit */
							/****************************/
							ps_PCI9054DMADescriptor[(*pdw_NbrOfDescriptorUsed) - 1].
							dw_NextDescriptorAddress = 8 | 2 | 1;
							
						}
					}
				}
			}
		} else {
			i_PCI3600_Intern_PCI9054_CompleteScatterGatherDescriptor (b_TransferDirection,
					b_InterruptFlag,
					1,
					dw_PCBufferPhysicalAddress,
					dw_PCBufferSize,
					dw_PCBufferReadPointer,
					0,
					dw_PCBufferNbrOfData + 1,
					dw_OnBoardBufferAddress,
					dw_OnBoardBufferSize,
					dw_OnBoardBufferReadPointer,
					dw_OnBoardBufferWritePointer,
					dw_OnBoardBufferNbrOfData,
					dw_NbrOfDescriptorAllocated,
					dw_DescriptorListPhysicalAddress,
					ps_PCI9054DMADescriptor,
					pdw_NbrOfDescriptorUsed,
					pdw_NbrOfDataTransferedByTheDescriptor);

		}
	}

#ifdef DEBUG_
	printk ("\tdw_NextDescriptorAddress %x\n", ps_PCI9054DMADescriptor[(*pdw_NbrOfDescriptorUsed) - 1].dw_NextDescriptorAddress);
	printk ("*pdw_NbrOfDescriptorUsed %x\n", *pdw_NbrOfDescriptorUsed);
	printk ("*pdw_NbrOfDataTransferedByTheDescriptor %x\n", *pdw_NbrOfDataTransferedByTheDescriptor);
#endif

	return (i_ReturnValue);

}

/*i_PCI3600_Intern_PCI9054_ChainingScatterGatherDescriptors*/
/*+----------------------------------------------------------------------------+*/
/*| Function Name : i_PCI3600_Intern_PCI9054_ChainingScatterGatherDescriptors()|*/
/*+----------------------------------------------------------------------------+*/
/*| Task :                                                                     |*/
/*  chaining the descriptor List for the DMA transfer                           */
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters :                                                         |*/
/*  pstr_DMAControllerInfos ps_DMAControllersInfos : DMA Channel Information    */
/*  uint8_t b_DMAChannel : DMA Channel index                                      */
/*  pstr_DescriptorInfos ps_DescriptorsInfos : Descriptor Information           */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters :                                                        |*/
/*                                                                              */
/*+----------------------------------------------------------------------------+*/
/*| Return Value :                                                             |*/
/*         > 0 : Warning                                                        */
/*         0 : No Error                                                         */
/*+----------------------------------------------------------------------------+*/
int __needlock i_PCI3600_Intern_PCI9054_ChainingScatterGatherDescriptors (pstr_DMAControllerInfos ps_DMAControllersInfos,
		uint8_t b_DMAChannel,
		pstr_DescriptorInfos ps_DescriptorsInfos)
{
	int i_ReturnValue = 0;
	uint8_t b_Cpt = 0;

	INTERN_MARK;

	for (b_Cpt = 0; b_Cpt < (ps_DMAControllersInfos [b_DMAChannel].b_NbrDMATranfer - 1); b_Cpt++) {
		ps_DescriptorsInfos	[ps_DMAControllersInfos [b_DMAChannel].
						ps_DMATransferInfo[b_Cpt].
						b_RessourceID].ps_PCI9054DMADescriptor[ps_DescriptorsInfos[
											ps_DMAControllersInfos [b_DMAChannel].
											ps_DMATransferInfo[b_Cpt].
											b_RessourceID
										]
							.dw_NbrOfDescriptorUsed - 1
						]
		.dw_NextDescriptorAddress =	(	ps_DescriptorsInfos	[
										ps_DMAControllersInfos [b_DMAChannel].
										ps_DMATransferInfo[b_Cpt].
										b_RessourceID
									].
						ps_PCI9054DMADescriptor	[
											ps_DescriptorsInfos	[
												ps_DMAControllersInfos [b_DMAChannel].
												ps_DMATransferInfo[b_Cpt].
												b_RessourceID
														]
											.dw_NbrOfDescriptorUsed - 1
										]
										.dw_NextDescriptorAddress & 0xD)
					|  	(	ps_DescriptorsInfos	[
										ps_DMAControllersInfos [b_DMAChannel].
										ps_DMATransferInfo[b_Cpt + 1].
										b_RessourceID
									].dw_DescriptorListPhysicalAddress & 0xFFFFFFF0UL
						);

#ifdef DEBUG_
	printk ("%s dw_NextDescriptorAddress %x\n", __FUNCTION__, ps_DescriptorsInfos	[ps_DMAControllersInfos [b_DMAChannel].
	                                 						ps_DMATransferInfo[b_Cpt].
	                                 						b_RessourceID].ps_PCI9054DMADescriptor[ps_DescriptorsInfos[
	                                 											ps_DMAControllersInfos [b_DMAChannel].
	                                 											ps_DMATransferInfo[b_Cpt].
	                                 											b_RessourceID
	                                 										]
	                                 							.dw_NbrOfDescriptorUsed - 1
	                                 						]
	                                 		.dw_NextDescriptorAddress);
#endif
	}


	return (i_ReturnValue);

}
/*i_PCI3600_Intern_UpdatePCBufferWithHeaderAndReturnPointer*/
/*+----------------------------------------------------------------------------+*/
/*| Function Name : i_PCI3600_Intern_UpdatePCBufferWithHeaderAndReturnPointer()|*/
/*+----------------------------------------------------------------------------+*/
/*| Task :                                                                     |*/
/*  Write in the PC Buffer the information for the user interrupt routine       */
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters :                                                         |*/
/*  uint8_t   b_CallLevel                                                         */
/*  uint8_t   b_Module : Module Index                                             */
/*  uint8_t   b_Source : Source                                                   */
/*  uint32_t* pdw_DMABufferAddress : Address of the DMA Buffer                    */
/*  uint32_t  dw_PCBufferSize : PC Buffer size in Byte                            */
/*  uint32_t dw_PCBufferReadPointer : PC Buffer read Pointer in uint32_t             */
/*  uint32_t dw_PCBufferWritePointer : PC Buffer write Pointer in uint32_t           */
/*  uint32_t dw_PCBufferNbrOfDataWritten : Nbr of Data Writen in the Buffer       */
/*                                       in uint32_t                               */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters :                                                        |*/
/*  uint32_t* pdw_ComputerBufferAddressKernelLevel : Array with the pointer of    */
/*                                                 the Buffer for Ring 0        */
/*  uint32_t* pdw_ComputerBufferAddressApplicLevel : Array with the pointer of    */
/*                                                 the Buffer for Ring 3        */
/*  uint32_t* pdw_NbrOfBuffer : Nbr of Buffer to give to the user interrupt       */
/*                            routine                                           */
/*+----------------------------------------------------------------------------+*/
/*| Return Value :                                                             |*/
/*         > 0 : Warning                                                        */
/*         0 : No Error                                                         */
/*+----------------------------------------------------------------------------+*/
int __needlock i_PCI3600_Intern_UpdatePCBufferWithHeaderAndReturnPointer (uint8_t   b_CallLevel,
		uint8_t   b_Module,
		uint8_t   b_Source,
		uint32_t* pdw_DMABufferAddress,
		uint32_t dw_PCBufferSize, // In Byte
		uint32_t dw_PCBufferReadPointer, // In uint32_t 
		uint32_t dw_PCBufferWritePointer, // In uint32_t 
		uint32_t dw_PCBufferNbrOfDataWritten, // In uint32_t 
		uint32_t* pdw_ComputerBufferAddressKernelLevel,
		uint32_t* pdw_ComputerBufferAddressApplicLevel,
		uint32_t* pdw_NbrOfBuffer)
{
	int i_ReturnValue = 0;
	uint32_t* pdw_BufferAddress = (uint32_t *)(uintptr_t)pdw_DMABufferAddress[b_CallLevel];
	uint32_t dw_NbrOfData = 0;

	INTERN_MARK;

	/*********************************/
	/* Test if the end of the buffer */
	/*********************************/
	if ((dw_PCBufferWritePointer + 1) == (dw_PCBufferSize / 4)) {
		dw_PCBufferWritePointer = 0;

	}
	/**************************************************/
	/* Test if the rest of the PC buffer is not break */
	/**************************************************/
	if ((dw_PCBufferWritePointer + 1 + dw_PCBufferNbrOfDataWritten) <= (dw_PCBufferSize / 4)) {
		pdw_BufferAddress [dw_PCBufferWritePointer] = (uint32_t)(b_Source) | (uint32_t)(b_Module << 2) | (uint32_t)(dw_PCBufferNbrOfDataWritten << 4);

		*pdw_NbrOfBuffer = 1;

		pdw_ComputerBufferAddressKernelLevel [0] = (uint32_t)(pdw_DMABufferAddress[PCI3600_RING_0] + (dw_PCBufferWritePointer * 4));

		pdw_ComputerBufferAddressApplicLevel[0] = (uint32_t)(pdw_DMABufferAddress[PCI3600_RING_3] + (dw_PCBufferWritePointer * 4));

	} else {
		*pdw_NbrOfBuffer = 2;

		dw_NbrOfData = (dw_PCBufferSize / 4) - (dw_PCBufferWritePointer + 1);

		pdw_BufferAddress [dw_PCBufferWritePointer] = (uint32_t)(b_Source) | (uint32_t)(b_Module << 2) | (uint32_t)( dw_NbrOfData << 4);

		pdw_ComputerBufferAddressKernelLevel [0] = (uint32_t)(pdw_DMABufferAddress[PCI3600_RING_0] + (dw_PCBufferWritePointer * 4));

		pdw_ComputerBufferAddressApplicLevel[0] = (uint32_t)(pdw_DMABufferAddress[PCI3600_RING_3] + (dw_PCBufferWritePointer * 4));

		dw_NbrOfData = dw_PCBufferNbrOfDataWritten - dw_NbrOfData;

		pdw_BufferAddress [0] = (uint32_t)(b_Source) | (uint32_t)(b_Module << 2) | (uint32_t)( dw_NbrOfData << 4);

		pdw_ComputerBufferAddressKernelLevel [1] = pdw_DMABufferAddress[PCI3600_RING_0];

		pdw_ComputerBufferAddressApplicLevel[1] = pdw_DMABufferAddress[PCI3600_RING_3];

	}
	return (i_ReturnValue);

}

/* reset subsystems state */
static void v_PCI3600_Reset_Subsys_State(struct pci_dev *pdev)
{
	int i;
	for (i = 0; i < APCI3600_PRIVDATA(pdev)->s_PCI3600_BoardInformation.b_AnalogInModuleNumber; i ++) 
	{
		APCI3600_PRIVDATA(pdev)->s_PCI3600_BoardInformation.s_AnalogInModuleInfos[i].b_ModuleInitStatus = 0;
	}
	for (i = 0; i < APCI3600_PRIVDATA(pdev)->s_PCI3600_BoardInformation.b_ChronometerNumber; i ++) 
	{
		APCI3600_PRIVDATA(pdev)->s_PCI3600_BoardInformation.s_ChronometerInfos[i].b_ChronometerInitStatus = 0;
	}
	for (i = 0; i < APCI3600_PRIVDATA(pdev)->s_PCI3600_BoardInformation.b_AnalogOutChannelNumber; i ++) 
	{
		APCI3600_PRIVDATA(pdev)->s_PCI3600_BoardInformation.s_AnalogOutInfos[i].b_ChannelInitStatus = 0;
	}
}


/*i_PCI3600_Intern_CloseHardware*/
/*$/$*                                                                          */
/*+----------------------------------------------------------------------------+*/
/*| Function's Name   : int i_PCI3600_Intern_CloseHardware                   |*/
/*|               (pstr_PCI3600_GlobalStruct ps_PCI3600_GlobalStruct,          |*/
/*|                uint8_t                       b_BoardIndex,                    |*/
/*|                uint8_t                       b_ProcessIndex,                  |*/
/*|                uint8_t                       b_CallLevel)                     |*/
/*+----------------------------------------------------------------------------+*/
/*| Task              : Close the hardware for the APCI-3600 driver            |*/
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters  : -                                                      |*/
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters : -                                                      |*/
/*+----------------------------------------------------------------------------+*/
/*| Return Value      : TRUE  : No error occur                                 |*/
/*|                     FALSE : Error occur                                    |*/
/*+----------------------------------------------------------------------------+*/
/*$*$/                                                                          */
int __needlock i_PCI3600_Intern_CloseHardware (struct pci_dev *pdev)
{
	uint8_t b_Cpt = 0;

	INTERN_MARK;

	if (!pdev)
		return -1;

	/******************************************/
	/* Stop all analog input interrupt source */
	/******************************************/
	for (b_Cpt = 0; b_Cpt < APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			b_AnalogInModuleNumber; b_Cpt ++) {
		i_PCI3600_StopAnalogInModuleCyclicAcquisition (pdev,
				b_Cpt);

		i_PCI3600_ReleaseAnalogInModuleCyclicAcquisition (pdev,
				b_Cpt);

	}
	/*******************************************/
	/* Stop all analog output interrupt source */
	/*******************************************/
	for (b_Cpt = 0; b_Cpt < APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			b_AnalogOutChannelNumber; b_Cpt ++) {
		i_PCI3600_StopAnalogOutSignalGenerator (pdev,
				b_Cpt);

		i_PCI3600_ReleaseAnalogOutSignalGenerator (pdev,
				b_Cpt);

	}
	/*****************************************/
	/* Stop all Chronometer interrupt source */
	/*****************************************/
	for (b_Cpt = 0; b_Cpt < APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			b_ChronometerNumber; b_Cpt ++) {
		i_PCI3600_StopChronometerModuleCyclicAcquisition (pdev,
				b_Cpt);

		i_PCI3600_ReleaseChronometerModuleCyclicAcquisition (pdev,
				b_Cpt);

	}

	/* reset state */

	// Begin TEST CG 17/11/2005
	/**************************************/
	/* Reset all the Local DMA Controller */
	/**************************************/
	OUTPDW_MEM (GET_MEM_BAR3(pdev)+
				PCI3600_ON_BOARD_LOCAL_DMA_CONTROLLER_OFFSET,0,0);
	/************************************/
	/* Reset all the start of the board */
	/************************************/
	OUTPDW_MEM (GET_MEM_BAR3(pdev) +
				PCI3600_CLOCK_BUS_GENERAL_OFFSET,4,0);
	// End TEST CG 17/11/2005
	for (b_Cpt = 0; b_Cpt < APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			s_DMAControllersInfos [PCI3600_DMA_CHANNEL_0].
			b_NbrDMATranfer; b_Cpt ++) {
		/*****************************************************/
		/* Abort the DMA Transfer if started by this process */
		/*****************************************************/
		if (APCI3600_PRIVDATA(pdev)->
				s_PCI3600_BoardInformation.
				s_DMAControllersInfos [PCI3600_DMA_CHANNEL_0].
				b_InUse == 1) {
			i_PCI3600_Primary_PCI9054AbortDMATransfer (GET_MEM_BAR0(pdev),
					PCI3600_DMA_CHANNEL_0);
		}
	}
	
	/* reset states */
	v_PCI3600_Reset_Subsys_State(pdev);

	/* clean event FIFO */
	apci3600_evt_empty(pdev);

	/* remove anyavailable data info */
	apci3600_clear_available_data(pdev);

	/* reset data buffer */ 
	i_ADDIUTILS_ResetDMABuffer(pdev);

	return (0);

}
///*Error __stdcall e_PCI3600_Intern_CallBackCloseHardware*/
///*$/$*                                                                          */
///*+----------------------------------------------------------------------------+*/
///*| Function's Name   : Error __stdcall e_PCI3600_Intern_CallBackCloseHardware |*/
///*|               ( Void* pArgs, Void* pContext)                               |*/
///*+----------------------------------------------------------------------------+*/
///*| Task              : Close the hardware for the APCI-3600 driver            |*/
///*+----------------------------------------------------------------------------+*/
///*| Input Parameters  : -                                                      |*/
///*+----------------------------------------------------------------------------+*/
///*| Output Parameters : -                                                      |*/
///*+----------------------------------------------------------------------------+*/
///*| Return Value      : TRUE  : No error occur                                 |*/
///*|                     FALSE : Error occur                                    |*/
///*+----------------------------------------------------------------------------+*/
///*$*$/                                                                          */
//Error __stdcall e_PCI3600_Intern_CallBackCloseHardware (Void* pArgs, Void* pContext)
//        {
//        int i_ReturnValue = 0;
//        uint8_t b_BoardCpt = 0;
//        // Begin CG 18/03/05 : 0101-0205 -> 0102-0305 : Kithara 7
//        uint8_t b_ProcessIndex;
//        uint8_t b_ProcessCpt;
//        // End CG 18/03/05 : 0101-0205 -> 0102-0305 : Kithara 7
//
//#ifdef _KITHARA_7_
//
//        SystemHandlerUserContext * ps_SystemHandlerUserContext  = (SystemHandlerUserContext *) pContext;
//        // Begin CG 18/03/05 : 0101-0205 -> 0102-0305 : Kithara 7
//          // pstr_PCI3600_InterruptParameterStruct ps_PCI3600_InterruptParameter = (str_PCI3600_InterruptParameterStruct *)pArgs;
//          // pstr_PCI3600_GlobalStruct  ps_PCI3600_GlobalStruct    = (pstr_PCI3600_GlobalStruct) ps_PCI3600_InterruptParameter -> pv_PCI3600_GlobalStruct;
//        pstr_PCI3600_GlobalStruct  ps_PCI3600_GlobalStruct    = (pstr_PCI3600_GlobalStruct) pArgs;
//        // End CG 18/03/05 : 0101-0205 -> 0102-0305 : Kithara 7
//        uint8_t  b_CallLevel = PCI3600_RING_0;
//
//        if (ps_SystemHandlerUserContext->eventType == KS_SYSTEM_PROCESS_ABORT)
//           {
//           /*Test if error occur*/
//           if (ps_PCI3600_GlobalStruct != NULL)
//              {
//              // Begin CG 18/03/05 : 0101-0205 -> 0102-0305 : Kithara 7
//
//              for (b_ProcessCpt = 0; b_ProcessCpt < PCI3600_MAX_PROCESS; b_ProcessCpt ++)
//                 {
//                 if (ps_PCI3600_GlobalStruct ->
//                     s_ProcessInformation [b_ProcessCpt].
//                     dw_ProcessID == ps_SystemHandlerUserContext -> currentProcessId)
//                    {
//                    b_ProcessIndex = b_ProcessCpt;
//                    break;
//
//                    }
//                 }
//              // End CG 18/03/05 : 0101-0205 -> 0102-0305 : Kithara 7
//
//              if (// CG 18/03/05 : 0101-0205 -> 0102-0305 : Kithara 7
//                  b_ProcessCpt < PCI3600_MAX_PROCESS)
//                 {
//                 for (b_BoardCpt = 0; b_BoardCpt < PCI3600_MAX_BOARD; b_BoardCpt ++)
//                    {
//                    i_ReturnValue = i_PCI3600_Intern_CloseHardware(ps_PCI3600_GlobalStruct,
//                                                                   b_BoardCpt,
//                                                                   b_ProcessIndex,
//                                                                   b_CallLevel);
//
//                    }
//                 }
//              }
//           }
//#endif
//
//        return(i_ReturnValue);
//
//        }
///*v_PCI3600_Intern_CallCriticalFunction*/
///*+----------------------------------------------------------------------------+*/
///*| Function's Name   : v_PCI3600_Intern_CallCriticalFunction                  |*/
///*+----------------------------------------------------------------------------+*/
///*| Task              : Call a critical function                               |*/
///*+----------------------------------------------------------------------------+*/
///*| Input Parameters  : -                                                      |*/
///*+----------------------------------------------------------------------------+*/
///*| Output Parameters : -                                                      |*/
///*+----------------------------------------------------------------------------+*/
///*| Return Value      : -                                                      |*/
///*+----------------------------------------------------------------------------+*/
//void __cdecl v_PCI3600_Intern_CallCriticalFunction (uint8_t                         b_CriticalSelection,
//                                                    uint8_t                         b_CallLevel,
//                                                    uint8_t                         b_BoardIndex,
//                                                    uint8_t                         b_ProcessIndex,
//                                                    str_PCI3600_GlobalStruct * ps_PCI3600_GlobalStruct,
//                                                    uint8_t                         b_SelectedCriticalFunction,
//                                                    uint32_t                        dw_InputArgNbr,
//                                                    uint32_t                        dw_OutputArgNbr,
//                                                    ...)
//        {
//        uint8_t                         b_ArgCpt;
//        uint8_t                         b_SelectedProcess;
//        uint8_t                         b_SearchAvailableProcess;
//        uint32_t*                     pdw_Arg        = (uint32_t*) &dw_OutputArgNbr;
//        uint32_t*                     pdw_ArgOut     = NULL;
//        Handle                       h_Handle     = NULL;
//        Error                        e_Error      = 0;
//        CallBackProc                 e_Function;
//        pstr_CriticalFunctionArg     ps_CriticalFctArg = 0;
//
//        /*************************/
//        /* Save the board index  */
//        /*************************/
//        ps_PCI3600_GlobalStruct->
//        s_ProcessInformation[b_ProcessIndex].
//        s_CriticalFctArg [b_BoardIndex].
//        dw_InputArg [1] = (uint32_t)  b_BoardIndex;
//
//        /**************************/
//        /* Save the process index */
//        /**************************/
//        ps_PCI3600_GlobalStruct->
//        s_ProcessInformation[b_ProcessIndex].
//        s_CriticalFctArg [b_BoardIndex].
//        dw_InputArg [2] = (uint32_t)  b_ProcessIndex;
//
//        /**********************/
//        /* Save all argumenst */
//        /**********************/
//        for (b_ArgCpt = 0; b_ArgCpt < dw_InputArgNbr; b_ArgCpt ++)
//           {
//           ps_PCI3600_GlobalStruct->
//           s_ProcessInformation[b_ProcessIndex].
//           s_CriticalFctArg [b_BoardIndex].
//           dw_InputArg [3 + b_ArgCpt] = pdw_Arg [1 + b_ArgCpt];
//
//           }
//        /*********************************************************/
//        /* Test if critical selection and not interrupt function */
//        /*********************************************************/
//        if ((b_CriticalSelection == ADDIDATA_CRITICAL_SECTION) && (b_CallLevel == 0))
//           {
//           /*****************************************************************/
//           /* Search if a interrupt handle are availbale for this interrupt */
//           /*****************************************************************/
//           for (b_SearchAvailableProcess = 0, b_SelectedProcess = b_ProcessIndex;
//                (b_SearchAvailableProcess < PCI3600_MAX_PROCESS) && (h_Handle == NULL);
//                b_SearchAvailableProcess = b_SearchAvailableProcess + 1, b_SelectedProcess = (b_SelectedProcess + 1) % PCI3600_MAX_PROCESS)
//              {
//              /*****************************************************************/
//              /* Test if handle != null and primary function address 0 != NULL */
//              /*****************************************************************/
//              if ((ps_PCI3600_GlobalStruct->
//                   s_ProcessInformation [b_SelectedProcess].
//                   s_ProcessInterruptInformations.
//                   s_InterruptSingleInformation [ps_PCI3600_GlobalStruct->
//                                                 s_SingleBoardInformation [b_BoardIndex].
//                                                 s_HardwareInformations.
//                                                 b_InterruptNbr].
//                   h_InterruptIdentifier != NULL) &&
//                  (ps_PCI3600_GlobalStruct->
//                   s_ProcessInformation [b_SelectedProcess].
//                   s_ProcessInterruptInformations.
//                   v_CriticalFunctionArray [1] [b_SelectedCriticalFunction] != NULL))
//                 {
//                 /*****************************/
//                 /* Save the interrupt handle */
//                 /*****************************/
//                 h_Handle = ps_PCI3600_GlobalStruct->
//                            s_ProcessInformation [b_SelectedProcess].
//                            s_ProcessInterruptInformations.
//                            s_InterruptSingleInformation [ps_PCI3600_GlobalStruct->
//                                                          s_SingleBoardInformation [b_BoardIndex].
//                                                          s_HardwareInformations.
//                                                          b_InterruptNbr].
//                            h_InterruptIdentifier;
//
//                 break;
//
//                 }
//              }
//           }
//        /**************************************/
//        /* Test if interrupt handle available */
//        /**************************************/
//        if (h_Handle != NULL)
//           {
//           /*****************************************/
//           /* Save the driver ring 0 struct address */
//           /*****************************************/
//           ps_PCI3600_GlobalStruct->
//           s_ProcessInformation[b_ProcessIndex].
//           s_CriticalFctArg [b_BoardIndex].
//           dw_InputArg [0] = (uint32_t) ps_PCI3600_GlobalStruct->
//                                     s_ProcessInformation[b_ProcessIndex].
//                                     ps_PCI3600_GlobalStructRing0;
//
//           /***********************************/
//           /* Get the ring 0 variable address */
//           /***********************************/
//           ps_CriticalFctArg = ps_PCI3600_GlobalStruct->
//                               s_ProcessInformation[b_ProcessIndex].
//                               ps_CriticalFctArgPtr [1] + b_BoardIndex;
//
//           /*******************************************/
//           /* Get the primary function ring 0 address */
//           /*******************************************/
//           e_Function = ps_PCI3600_GlobalStruct->
//                        s_ProcessInformation [b_SelectedProcess].
//                        s_ProcessInterruptInformations.
//                        v_CriticalFunctionArray [1] [b_SelectedCriticalFunction];
//
//           /*****************************/
//           /* Call the primary function */
//           /*****************************/
//           e_Error = KS_execSyncFunction (h_Handle,
//                                          e_Function,
//                                          (void *) ps_CriticalFctArg,
//                                          0);
//
//           }
//        else
//           {
//           /**********************************/
//           /* Save the driver struct address */
//           /**********************************/
//           ps_PCI3600_GlobalStruct->
//           s_ProcessInformation[b_ProcessIndex].
//           s_CriticalFctArg [b_BoardIndex].
//           dw_InputArg [0] = (uint32_t) ps_PCI3600_GlobalStruct;
//
//           ps_CriticalFctArg = ps_PCI3600_GlobalStruct->
//                               s_ProcessInformation[b_ProcessIndex].
//                               ps_CriticalFctArgPtr [b_CallLevel] + b_BoardIndex;
//
//           /*******************************************/
//           /* Get the ring 3 primary function address */
//           /*******************************************/
//           if (b_CallLevel == 0)
//              {
//              e_Function = v_Global_CriticalFunctionList [b_SelectedCriticalFunction];
//
//              }
//           else
//              {
//              e_Function = ps_PCI3600_GlobalStruct->
//                           s_ProcessInformation [b_ProcessIndex].
//                           s_ProcessInterruptInformations.
//                           v_CriticalFunctionArray [1] [b_SelectedCriticalFunction];
//
//              }
//           /*****************************/
//           /* Call the primary function */
//           /*****************************/
//           e_Error = e_Function ((void *) ps_CriticalFctArg);
//
//           }
//        /****************************/
//        /* Get all return arguments */
//        /****************************/
//        for (b_ArgCpt = 0; b_ArgCpt < dw_OutputArgNbr; b_ArgCpt ++)
//           {
//           pdw_ArgOut  = (uint32_t*) pdw_Arg [1 + b_ArgCpt + (uint8_t) dw_InputArgNbr];
//           *pdw_ArgOut = ps_PCI3600_GlobalStruct->
//                         s_ProcessInformation[b_ProcessIndex].
//                         s_CriticalFctArg [b_BoardIndex].
//                         dw_OutputArg [b_ArgCpt];
//
//           }
//        }



/*e_PCI3600_Intern_IncrAnaInpChronoBufferReadPointer*/
/*+----------------------------------------------------------------------------+*/
/*| Function Name : e_PCI3600_Intern_IncrAnaInpChronoBufferReadPointer () |*/
/*+----------------------------------------------------------------------------+*/
/*| Task :                                                                     |*/
/*  Critical function to increment the PC Read pointer                          */
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters :                                                         |*/
/*         pstr_CriticalFunctionArg ps_Args : Arguments for the critical        */
/*                                            function                          */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters :                                                        |*/
/*                                                                              */
/*+----------------------------------------------------------------------------+*/
/*| Return Value :                                                             |*/
/*         0 : No Error                                                         */
/*+----------------------------------------------------------------------------+*/
//Error __stdcall e_PCI3600_Intern_IncrAnaInpChronoBufferReadPointer (pstr_CriticalFunctionArg ps_Args)
int __needlock i_PCI3600_Intern_IncrAnaInpChronoBufferReadPointer(struct pci_dev *pdev,
		uint32_t dw_IncNbr)
{
	int i_ReturnValue = 0;
	uint32_t dw_NbrOfData = 0;


	INTERN_MARK;

	/***********************************/
	/* Test if the buffer is not empty */
	/***********************************/
	if (APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			s_AnaInpChronomPCDMABufferInfos.
			b_Empty == 0)
	{
		/*********************************/
		/* Test if the end of the buffer */
		/*********************************/
		if ((APCI3600_PRIVDATA(pdev)->
				s_PCI3600_BoardInformation.
				s_AnaInpChronomPCDMABufferInfos.
				dw_ReadPointer + 1) == (APCI3600_PRIVDATA(pdev)->
										s_PCI3600_BoardInformation.
										s_AnaInpChronomPCDMABufferInfos.
										dw_BufferSize / 4)) {
			APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			s_AnaInpChronomPCDMABufferInfos.
			dw_ReadPointer = 0;

#ifdef DEBUG_
			printk ("%s dw_ReadPointer %u\n", __FUNCTION__, APCI3600_PRIVDATA(pdev)->
					s_PCI3600_BoardInformation.
					s_AnaInpChronomPCDMABufferInfos.
					dw_ReadPointer);
#endif

			if (APCI3600_PRIVDATA(pdev)->
					s_PCI3600_BoardInformation.
					s_AnaInpChronomPCDMABufferInfos.
					dw_ReadPointer == APCI3600_PRIVDATA(pdev)->
					s_PCI3600_BoardInformation.
					s_AnaInpChronomPCDMABufferInfos.
					dw_WritePointer) {
				APCI3600_PRIVDATA(pdev)->
				s_PCI3600_BoardInformation.
				s_AnaInpChronomPCDMABufferInfos.
				b_Empty = 1;

			}
		}
		/***********************************/
		/* Test if the buffer is not empty */
		/***********************************/
		if (APCI3600_PRIVDATA(pdev)->
				s_PCI3600_BoardInformation.
				s_AnaInpChronomPCDMABufferInfos.
				b_Empty == 0) {
			/*****************************************************/
			/* Determine the number of data in the PC RAM buffer */
			/*****************************************************/
			if (APCI3600_PRIVDATA(pdev)->
					s_PCI3600_BoardInformation.
					s_AnaInpChronomPCDMABufferInfos.
					b_Full == 0) {
				if (APCI3600_PRIVDATA(pdev)->
						s_PCI3600_BoardInformation.
						s_AnaInpChronomPCDMABufferInfos.
						dw_ReadPointer > APCI3600_PRIVDATA(pdev)->
						s_PCI3600_BoardInformation.
						s_AnaInpChronomPCDMABufferInfos.
						dw_WritePointer  ) {
					dw_NbrOfData = ((APCI3600_PRIVDATA(pdev)->
									 s_PCI3600_BoardInformation.
									 s_AnaInpChronomPCDMABufferInfos.
									 dw_BufferSize / 4) - APCI3600_PRIVDATA(pdev)->
									s_PCI3600_BoardInformation.
									s_AnaInpChronomPCDMABufferInfos.
									dw_ReadPointer) + APCI3600_PRIVDATA(pdev)->
								   s_PCI3600_BoardInformation.
								   s_AnaInpChronomPCDMABufferInfos.
								   dw_WritePointer;

				} else {
					dw_NbrOfData = APCI3600_PRIVDATA(pdev)->
								   s_PCI3600_BoardInformation.
								   s_AnaInpChronomPCDMABufferInfos.
								   dw_WritePointer - APCI3600_PRIVDATA(pdev)->
								   s_PCI3600_BoardInformation.
								   s_AnaInpChronomPCDMABufferInfos.
								   dw_ReadPointer;

				}
			} else {
				dw_NbrOfData = APCI3600_PRIVDATA(pdev)->
							   s_PCI3600_BoardInformation.
							   s_AnaInpChronomPCDMABufferInfos.
							   dw_BufferSize / 4;

			}
			if (dw_IncNbr > dw_NbrOfData) {
				dw_IncNbr = dw_NbrOfData;

			}
			APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			s_AnaInpChronomPCDMABufferInfos.
			dw_ReadPointer = (APCI3600_PRIVDATA(pdev)->
							  s_PCI3600_BoardInformation.
							  s_AnaInpChronomPCDMABufferInfos.
							  dw_ReadPointer + dw_IncNbr) % (APCI3600_PRIVDATA(pdev)->
															 s_PCI3600_BoardInformation.
															 s_AnaInpChronomPCDMABufferInfos.
															 dw_BufferSize / 4);

#ifdef DEBUG_
			printk ("%s dw_ReadPointer %u dw_IncNbr %u\n", __FUNCTION__, APCI3600_PRIVDATA(pdev)->
					s_PCI3600_BoardInformation.
					s_AnaInpChronomPCDMABufferInfos.
					dw_ReadPointer, dw_IncNbr);
#endif

			APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			s_AnaInpChronomPCDMABufferInfos.
			b_Full = 0;

			if (APCI3600_PRIVDATA(pdev)->
					s_PCI3600_BoardInformation.
					s_AnaInpChronomPCDMABufferInfos.
					dw_ReadPointer == APCI3600_PRIVDATA(pdev)->
					s_PCI3600_BoardInformation.
					s_AnaInpChronomPCDMABufferInfos.
					dw_WritePointer) {
				APCI3600_PRIVDATA(pdev)->
				s_PCI3600_BoardInformation.
				s_AnaInpChronomPCDMABufferInfos.
				b_Empty = 1;

			} else {}
		}
	}

	return (i_ReturnValue);

}

/*e_PCI3600_Intern_IncrAnaOupBufferWritePointer*/
/*+----------------------------------------------------------------------------+*/
/*| Function Name : e_PCI3600_Intern_IncrAnaOupBufferWritePointer ()      |*/
/*+----------------------------------------------------------------------------+*/
/*| Task :                                                                     |*/
/*  Critical function to increment the PC Write pointer                         */
/*+----------------------------------------------------------------------------+*/
/*| Input Parameters :                                                         |*/
/*         pstr_CriticalFunctionArg ps_Args : Arguments for the critical        */
/*                                            function                          */
/*+----------------------------------------------------------------------------+*/
/*| Output Parameters :                                                        |*/
/*                                                                              */
/*+----------------------------------------------------------------------------+*/
/*| Return Value :                                                             |*/
/*         0 : No Error                                                         */
/*+----------------------------------------------------------------------------+*/
//Error __stdcall e_PCI3600_Intern_IncrAnaOupBufferWritePointer (pstr_CriticalFunctionArg ps_Args)
int __needlock i_PCI3600_Intern_IncrAnaOupBufferWritePointer(struct pci_dev *pdev,
		uint8_t b_Channel,
		uint32_t dw_NbrOfWrittenValues)
{
	int i_ReturnValue = 0;

	INTERN_MARK;

	disable_irq (APCI3600_PRIVDATA(pdev)->
				 s_PCI3600_BoardInformation.
				 s_HardwareInformations.
				 b_InterruptNbr);

	/****************************/
	/* Update the Write Pointer */
	/****************************/
	APCI3600_PRIVDATA(pdev)->
	s_PCI3600_BoardInformation.
	s_AnalogOutInfos[b_Channel].
	s_AnalogOutPCDMABufferInfos.
	dw_WritePointer = (APCI3600_PRIVDATA(pdev)->
					   s_PCI3600_BoardInformation.
					   s_AnalogOutInfos[b_Channel].
					   s_AnalogOutPCDMABufferInfos.
					   dw_WritePointer + dw_NbrOfWrittenValues) % (APCI3600_PRIVDATA(pdev)->
							   s_PCI3600_BoardInformation.
							   s_AnalogOutInfos[b_Channel].
							   s_AnalogOutPCDMABufferInfos.
							   dw_BufferSize / 4);

	/****************************/
	/* Actualise the empty flag */
	/****************************/
	APCI3600_PRIVDATA(pdev)->
	s_PCI3600_BoardInformation.
	s_AnalogOutInfos[b_Channel].
	s_AnalogOutPCDMABufferInfos.
	b_Empty = 0;

	/***************************/
	/* Actualise the full flag */
	/***************************/
	if (APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			s_AnalogOutInfos[b_Channel].
			s_AnalogOutPCDMABufferInfos.
			dw_WritePointer == APCI3600_PRIVDATA(pdev)->
			s_PCI3600_BoardInformation.
			s_AnalogOutInfos[b_Channel].
			s_AnalogOutPCDMABufferInfos.
			dw_ReadPointer )
	{
		APCI3600_PRIVDATA(pdev)->
		s_PCI3600_BoardInformation.
		s_AnalogOutInfos[b_Channel].
		s_AnalogOutPCDMABufferInfos.
		b_Full = 1;

	}

	enable_irq (APCI3600_PRIVDATA(pdev)->
				s_PCI3600_BoardInformation.
				s_HardwareInformations.
				b_InterruptNbr);

	return (i_ReturnValue);

}

unsigned long  __needlock i_PCI3600_Intern_GetNumberOfData(struct pci_dev *pdev)
{
	unsigned long readptr = APCI3600_PRIVDATA (pdev)->s_PCI3600_BoardInformation.s_AnaInpChronomPCDMABufferInfos.dw_ReadPointer;
	unsigned long writeptr =APCI3600_PRIVDATA (pdev)->s_PCI3600_BoardInformation.s_AnaInpChronomPCDMABufferInfos.dw_WritePointer;	
	unsigned long sz = APCI3600_PRIVDATA (pdev)->s_PCI3600_BoardInformation.s_AnaInpChronomPCDMABufferInfos.dw_BufferSize;
	if ( readptr<writeptr)
		return writeptr-readptr;
	if ( readptr>writeptr )
		return sz-readptr+writeptr;
	return 0;
}
