/** @file transducer-kapi.c
 
   Contains analog input functions for transducer measure.
 
   @par CREATION  
   @author Krauth Julien
   @date   09.10.2006
   
   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim   
   
   @par LICENCE
   @verbatim
   Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
        
        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 should have received a copy of the GNU General Public License along with 
   this program; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

   You shoud also find the complete GPL in the COPYING file 
   accompanying this source code.
   @endverbatim   
 */ 

#include "apci3701-private.h"

EXPORT_SYMBOL(i_APCI3701_InitTransducerChannel);
EXPORT_SYMBOL(i_APCI3701_InitAnalogInputAutorefresh);
EXPORT_SYMBOL(i_APCI3701_StartAnalogInputAutorefresh);
EXPORT_SYMBOL(i_APCI3701_StopAnalogInputAutorefresh);
EXPORT_SYMBOL(i_APCI3701_ReadAnalogInputAutorefreshValue);
EXPORT_SYMBOL(i_APCI3701_GetAutorefreshStatus);
EXPORT_SYMBOL(i_APCI3701_EnableDisableAnalogInputHardwareTrigger);

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

/** Enable, disable and initialise the analog input hardware trigger
 *
 * @param[in]  pdev : PCI Device struct
 * @param[in]   b_HardwareTrigger : 0 : disable the hardware trigger<br>
 *              					1 : enable the hardware trigger
 * @param[in]   b_HardwareTriggerLevel : ADDIDATA_LOW: If the hardware
 *              	                                	  trigger is used, it triggers<br>
 *            	      	                    	          from "1" to "0"<br>
 *              	        	                          ADDIDATA_HIGH: If the hardware trigger is used, it<br>
 *                      	        	                  triggers from "0" to "1"<br>
 *                          	        	              ADDIDATA_LOW_HIGH: If the hardware trigger is used, it<br>
 *                                  	        	      triggers from "0" to "1" or from "1" to "0"
 * @param[in]   b_HardwareTriggerAction : Trigger action selection<br>
 *            			            	ADDIDATA_TRIGGER_START_A_SINGLE_CONVERSION	  0<br>
 *            			            	ADDIDATA_ONE_SHOT_TRIGGER					  1<br>
 *            			            	ADDIDATA_TRIGGER_START_A_SEQUENCE_SERIES	  2<br>
 *            			            	ADDIDATA_TRIGGER_START_A_SINGLE_SEQUENCE	  3<br>
 *            			            	ADDIDATA_TRIGGER_START_A_SCAN_SERIES	      6<br>
 *            			            	ADDIDATA_TRIGGER_START_A_SINGLE_SCAN  		  7<br>
 *            			            	ADDIDATA_TRIGGER_START_A_AUTO_REFRESH_SERIES 10<br>
 *            			            	ADDIDATA_TRIGGER_START_A_SINGLE_AUTO_REFRESH 11<br>
 * @param[in] dw_HardwareTriggerCount  : Hardware trigger counter.<br>
 *                  		             Define the number of trigger events before the action occur (> 0)
 *
 *
 * @retval  0 : No error                                         
 * @retval  1 : The handle parameter of the board is wrong       
 * @retval  2 : Wrong hardware trigger parameter                 
 * @retval  3 : Wrong hardware trigger level parameter           
 * @retval  4 : Wrong hardware trigger action parameter          
 * @retval  5 : Wrong hardware trigger count parameter           
 * @retval  6 : No analog input functionality available          
 * @retval  7 : A conversion is already started                  
 */
int i_APCI3701_EnableDisableAnalogInputHardwareTrigger (struct pci_dev * pdev,
							                            uint8_t   b_HardwareTrigger,
							                            uint8_t   b_HardwareTriggerLevel,   
							                            uint8_t   b_HardwareTriggerAction,  
							                            uint32_t  dw_HardwareTriggerCount)  
{
	uint32_t  dw_ResetMask = 0;
	uint32_t  dw_SetMask = 0;
	uint32_t  dw_WriteValueDWord = 0; 
	uint32_t  dw_ReadMaskDWord = 0;
	uint32_t  dw_ReadValueDWord = 0;

	if (!pdev) return 1;

	/* Tests the hardware trigger flag */
	if ( (b_HardwareTrigger != ADDIDATA_ENABLE) && (b_HardwareTrigger != ADDIDATA_DISABLE) )
		return 2;
		
	if ((b_HardwareTriggerAction != ADDIDATA_TRIGGER_START_A_SINGLE_CONVERSION) 
		&& (b_HardwareTriggerAction != ADDIDATA_ONE_SHOT_TRIGGER)
		&& (b_HardwareTriggerAction != ADDIDATA_TRIGGER_START_A_SEQUENCE_SERIES)
		&& (b_HardwareTriggerAction != ADDIDATA_TRIGGER_START_A_SINGLE_SEQUENCE)
		&& (b_HardwareTriggerAction != ADDIDATA_TRIGGER_START_A_SCAN_SERIES)
		&& (b_HardwareTriggerAction != ADDIDATA_TRIGGER_START_A_SINGLE_SCAN)
		&& (b_HardwareTriggerAction != ADDIDATA_TRIGGER_START_A_AUTO_REFRESH_SERIES)
		&& (b_HardwareTriggerAction != ADDIDATA_TRIGGER_START_A_SINGLE_AUTO_REFRESH)
		&& (b_HardwareTrigger == ADDIDATA_ENABLE))
	 		/* Wrong trigger mode */
			return 3;    

	if ((b_HardwareTriggerLevel != ADDIDATA_LOW) && (b_HardwareTriggerLevel != ADDIDATA_HIGH) && (b_HardwareTriggerLevel != ADDIDATA_LOW_HIGH) && (b_HardwareTrigger == ADDIDATA_ENABLE))
		return 4;

	if (((dw_HardwareTriggerCount > 65535) || (dw_HardwareTriggerCount == 0)) && (b_HardwareTrigger == ADDIDATA_ENABLE))
		return 5;

	if (0 == APCI3701_PRIVDATA(pdev)->b_NumberOfAnalogInput)
		return 6;

	if (b_HardwareTrigger != ADDIDATA_DISABLE)
		{
		dw_ReadMaskDWord = 0x80000;
		INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, &dw_ReadValueDWord);
		dw_ReadValueDWord = dw_ReadValueDWord & dw_ReadMaskDWord;
	
		if (dw_ReadValueDWord == 0x00080000)
			/* Conversion started */
			return 7;
	           
		}

	if (b_HardwareTriggerAction == ADDIDATA_ONE_SHOT_TRIGGER)
		{
	  	/* Set the one shot trigger mode */
	    b_HardwareTriggerAction = 0;
	   
	    }
	else
	    {
	  	/* Test if Single channel trigger mode */
	  	if (b_HardwareTriggerAction == ADDIDATA_TRIGGER_START_A_SINGLE_CONVERSION)
	    	{
	 		/* Set the single channel trigger mode */
	     	b_HardwareTriggerAction = 1;
	  
			}
		}

	if (b_HardwareTrigger != ADDIDATA_DISABLE)
		{
	   	/*Enable the extern trigger, the level selection and set the trigger counter value */
		dw_SetMask = (uint32_t) (((uint32_t) b_HardwareTriggerLevel & 1)    << 2) |
	                  (uint32_t) (((uint32_t) b_HardwareTriggerLevel & 2)    << 0) |
	                  (uint32_t) (((uint32_t) (b_HardwareTriggerAction & 3)) << 3) |
	                  (uint32_t) (((uint32_t) dw_HardwareTriggerCount)       << 16);
		dw_ResetMask = 0xFFFF007E;
		INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_HARDWARE_TRIGGER, &dw_WriteValueDWord);
		dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
		OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_HARDWARE_TRIGGER, dw_WriteValueDWord); 
		}

	if (b_HardwareTrigger == ADDIDATA_ENABLE)
		{
        /* Enable the extern trigger */
		dw_SetMask = 0x1;
		dw_ResetMask = 0;
		INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_HARDWARE_TRIGGER, &dw_WriteValueDWord);
		dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
		OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_HARDWARE_TRIGGER, dw_WriteValueDWord); 
		}
	else
		{
        /*Reset the Enable bit */
		dw_SetMask = 0;
		dw_ResetMask = 0x1;
		INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_HARDWARE_TRIGGER, &dw_WriteValueDWord);
		dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
		OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_HARDWARE_TRIGGER, dw_WriteValueDWord); 
		}

	return 0;
}

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

/** Get the autorefresh status.
 * 
 * @param [in] pdev                 : The device to initialize.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Acquisition already started.
 */
int   i_APCI3701_GetAutorefreshStatus (struct pci_dev *pdev)
{
    if (!pdev)
    { 
    	return 1;
    }    

    /* Test if a conversion is already started */
    if ( APCI3701_ACQUISITION_STARTED(pdev) )
    {
	return 2;
    }
 
    return 0;
}    

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

/** Initialize the transducer of the specified channel.                                                 
 * 
 * @param [in] pdev                 : The device to initialize.
 * @param [in] w_Channel            : Channel number to configure (0 to 15).
 * @param [in] w_TrasnducerIndex    : Use i_APCI3701_GetTransducerIndex to get the transducer index.
 * @param [in] w_MasterClock        : NO MORE USE BUT WE NEED IT FOR COMPATIBILITY. give 0
 * @param [in] w_LeftRightClock     : NO MORE USE BUT WE NEED IT FOR COMPATIBILITY. give 0
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The channel parameter is wrong.
 * @retval 3: Acquisition already started.
 */
int   i_APCI3701_InitTransducerChannel (struct pci_dev *pdev,
										uint16_t w_Channel,
										uint16_t w_TrasnducerIndex,
										uint16_t w_MasterClock,
										uint16_t w_LeftRightClock)
{
	uint32_t dw_WriteConfig = 0;

    if (!pdev) return 1;
    
	if (w_Channel >= APCI3701_PRIVDATA(pdev)->b_NumberOfAnalogInput) return 2;    
	
	/* Test if a conversion is already started */
	if ( APCI3701_ACQUISITION_STARTED(pdev) )
		return 3;

	/* Set the transducer type and the transducer primary frequency */
	dw_WriteConfig = (uint32_t) ((uint32_t)(w_MasterClock) | (uint32_t)(w_LeftRightClock << 3) | (uint32_t)(w_TrasnducerIndex << 16));   
	OUTPDW_MEM (GET_MEM_BAR3(pdev), APCI3701_REG_TRANSDUCER_CONFIG_BASE + (w_Channel * 4), dw_WriteConfig);

	// Save the index into the private data of the device
	APCI3701_PRIVDATA(pdev)->transducers_type[w_Channel] = w_TrasnducerIndex;

	return 0;
}    

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

/** Initialize the autorefresh acquisition.                                                 
 * 
 * @param [in] pdev                 : The device to initialize.
 * @param [in] w_SequenceSize       : Number of channels in the sequence :(1,16).
 * @param [in] w_ChannelSequence    : Channel sequence.<br>
 *                                    E.g.: For an acquisition on both A/D chip on each 4 first channels<br>
 *                                    The sequence has to be:<br>
 *                                    w_ChannelSequence[0] = 0;<br>
 *                                    w_ChannelSequence[1] = 7;<br>
 *                                    w_ChannelSequence[2] = 1;<br>
 *                                    w_ChannelSequence[3] = 8;<br>
 *                                    w_ChannelSequence[4] = 2;<br>
 *                                    w_ChannelSequence[5] = 9;<br>
 *                                    w_ChannelSequence[6] = 3;<br>
 *                                    w_ChannelSequence[7] = 10;<br>
 * @param [in] b_DivisionFactor     : The converting time division factor sets the switching time from channel to channel.<br>
 *                                    The base time is the transducer frequency. For example if the transducer connected to<br>
 *                                    channel 0 uses the 14 kHz frequency and the division factor is set to 5<br>
 *                                    then the switching time fron channel 0 to the next is: 1 (14/5) = 0.357 ms.<br>
 *                                    It is comprised between 5 and 255.
 *
 * @retval	0	No error. 
 * @retval	1	The handle parameter of the board is wrong.
 * @retval	2	The division factor is wrong.
 * @retval	3	Acquisition already started.
 * @retval	4	incorrect w_SequenceSize (must be : (1,16) )
 */
int i_APCI3701_InitAnalogInputAutorefresh (struct pci_dev *pdev,
											uint32_t w_SequenceSize,
											uint32_t *w_ChannelSequence,
											uint8_t b_DivisionFactor)
{
    
	int i_SeqIndex = 0;
	uint32_t  dw_ResetMask = 0;
	uint32_t  dw_SetMask = 0;
	uint32_t dw_WriteValueDWord = 0; 
   
	if (!pdev) return 1;

	/* Frequency Division Factor must be comprised between 5 and 255 */	
	if (b_DivisionFactor < 5 ) 
		return 2; 

	switch(w_SequenceSize)
	{
		case 1 ... 16:
			break;
		default:
			return 4;
	}
	
	/* Test if a conversion is already started */
	if ( APCI3701_ACQUISITION_STARTED(pdev) )
		return 3;
	
   	/* Disable the delay*/
	dw_SetMask = 0x0UL;
	dw_ResetMask = 0x00040000UL;
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, &dw_WriteValueDWord);
	dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, dw_WriteValueDWord); 		
	
	/* Set the division factor */
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_DIVISION_FACTOR, b_DivisionFactor);
	
	/* Save some values in the driver structure */
	APCI3701_PRIVDATA(pdev)->w_SequenceSize = w_SequenceSize;		
	
	/* Set the channel sequence */
	for (i_SeqIndex=0; i_SeqIndex<w_SequenceSize; i_SeqIndex++) {
		
		/* Select the channel index */ 
		dw_SetMask = (uint32_t) (0x100UL | i_SeqIndex);
		dw_ResetMask = 0x20FFUL;
		INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_INDEX, &dw_WriteValueDWord);
		dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
		OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_INDEX, dw_WriteValueDWord); 
		
		/* Set the channel */ 
		dw_SetMask = (uint32_t) w_ChannelSequence[i_SeqIndex];
		dw_ResetMask = 0xFFUL;
		INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_CHANNEL_NUMBER, &dw_WriteValueDWord);
		dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
		OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_CHANNEL_NUMBER, dw_WriteValueDWord); 			
		
		/* Save some values in the driver structure */
		APCI3701_PRIVDATA(pdev)->w_ChannelSequence[i_SeqIndex] = w_ChannelSequence[i_SeqIndex];			
	} 
	
	/* Set the start sequence index */
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, &dw_WriteValueDWord);
	dw_WriteValueDWord &= ~ANALOG_SEQUENCE_START_BITMASK;
	
	/* The first channel */		
	dw_WriteValueDWord |= 0;				
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, dw_WriteValueDWord); 
	
	/* Set the stop sequence index */
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, &dw_WriteValueDWord);
	dw_WriteValueDWord &= ~ANALOG_SEQUENCE_STOP_BITMASK;
	
	/* Set the last channel */
	dw_WriteValueDWord |= ((w_SequenceSize - 1) << 8);
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, dw_WriteValueDWord);

	/* Set the continous mode and disable the DMA */
	dw_SetMask = 0x10000UL;
	dw_ResetMask = 0x230000UL;
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, &dw_WriteValueDWord);
	dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, dw_WriteValueDWord); 
          
	/* Clear the sequence counter */
	dw_SetMask = 0x0UL;
	dw_ResetMask = 0xFFFFFFFFUL;
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_COUNTER, &dw_WriteValueDWord);
	dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_COUNTER, dw_WriteValueDWord); 
	
	/* Clear the DMA transfer size */
	dw_SetMask = 0x0UL;
	dw_ResetMask = 0xFFFFFFFFUL;
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_DMA_TRANSFER_SIZE, &dw_WriteValueDWord);
	dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_DMA_TRANSFER_SIZE, dw_WriteValueDWord); 

	/* Clear the sequence index */
	dw_SetMask = 0x10000UL;
	dw_ResetMask = 0x0UL;
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_CLEAR_INDEX, &dw_WriteValueDWord);
	dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_CLEAR_INDEX, dw_WriteValueDWord); 		
                 
	return 0;
}
   
//----------------------------------------------------------------------------

/** Start the autorefresh acquisition.                                                 
 * 
 * @param [in] pdev                 : The device to initialize.
 *
 * @retval	0	No error. 
 * @retval	1	The handle parameter of the board is wrong.
 * @retval	2	Acquisition already started.
 */
int i_APCI3701_StartAnalogInputAutorefresh (struct pci_dev *pdev)
{
	uint32_t dw_WriteValueDWord = 0;  
	uint32_t  dw_ResetMask = 0;
	uint32_t  dw_SetMask = 0;    

	if (!pdev) return 1;

	/* Test if a conversion is already started */
	if ( APCI3701_ACQUISITION_STARTED(pdev) )
		return 2;
	
	/* Clear all DMA interrupt source */
	dw_SetMask = 0x35UL;
	dw_ResetMask = 0xFFFFFFFFUL;
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_ANALOG_INPUT_IRQ_STATUS, &dw_WriteValueDWord);
	dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_ANALOG_INPUT_IRQ_STATUS, dw_WriteValueDWord); 
	
	/* Clear the interrupt   */
	/* Clear the DMA         */
	/* Start the acquisition */
	dw_SetMask = 0x80000UL;
	dw_ResetMask = 0x300000UL;
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, &dw_WriteValueDWord);
	dw_WriteValueDWord = (dw_WriteValueDWord & (0xFFFFFFFFUL - dw_ResetMask)) | dw_SetMask;
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, dw_WriteValueDWord); 

	apci3701_data_wakeup(pdev);

	return 0;
}

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

/** Stop the autorefresh acquisition.                                                 
 * 
 * @param [in] pdev                 : The device to initialize.
 *
 * @retval	0	No error. 
 * @retval	1	The handle parameter of the board is wrong.
 * @retval	2	Acquisition not started.
 */
int i_APCI3701_StopAnalogInputAutorefresh (struct pci_dev *pdev)
{
	uint32_t dw_WriteValueDWord = 0; 

	if (!pdev) return 1;

	/* Test if a conversion is already started */
	if ( ! APCI3701_ACQUISITION_STARTED(pdev) )
		return 2;
	
	/* Stop the sequence */
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, &dw_WriteValueDWord);
	dw_WriteValueDWord &= ~ANALOG_SEQUENCE_START_STOP_BITMASK;
	OUTPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_CONTROL, dw_WriteValueDWord); 

	return 0;
}
	
//----------------------------------------------------------------------------

/** Read autorefresh acquisition.                                                 
 * 
 * @param [in]  pdev                 : The device to initialize.
 * @param [out] dw_ReadValue         : An array with each channel value.<br>
 *                                     Values are returned in the sequence order.
 * @param [out] dw_SequenceCounter   : Number of sequence.
 *                                     This value can be used to test if new value are available.

 * @retval	0	No error. 
 * @retval	1	The handle parameter of the board is wrong.
 * @retval	2	Acquisition not started.
 */
int i_APCI3701_ReadAnalogInputAutorefreshValue (struct pci_dev *pdev,
												uint32_t *dw_ReadValue,
												uint32_t *dw_SequenceCounter)
{ 
	int i_SeqIndex = 0;

	if (!pdev) return 1;
	
	/* Test if a conversion is already started */
	if ( ! APCI3701_ACQUISITION_STARTED(pdev) )
		return 2;

	/* Read the number of sequence */
	INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_COUNTER, dw_SequenceCounter);
		
	/* Read value for each channel in the sequence */
	for (i_SeqIndex=0; i_SeqIndex < APCI3701_PRIVDATA(pdev)->w_SequenceSize; i_SeqIndex++)
	{
		INPDW_MEM(GET_MEM_BAR3(pdev), (APCI3701_REG_AUTOREFRESH_VALUES_BASE + (APCI3701_PRIVDATA(pdev)->w_ChannelSequence[i_SeqIndex]*4)), &(dw_ReadValue[i_SeqIndex]));
	}

	return 0;
}

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