/** @file temp_inputs.c

Functions to read CJC values.

@par CREATION
@author Krauth Julien
@date   06.06.05

@par VERSION
@verbatim
$LastChangedRevision$
$LastChangedDate$
@endverbatim

@par COMPILER
@verbatim
Compiler	: gcc
Version	: gcc (GCC) 3.3.6 (Debian 1:3.3.6-5)
kernel	: 2.4.26
@endverbatim

@par UPDATES
@verbatim
Date			: 15.07.2005
Author		: Krauth Julien
Description	: Correction that permit to get value from all 16 thermocouple channels.

Date			: 15.06.2005
Author		: Krauth Julien
Description	: Add timeout management in OUTPDW_WAIT_READY and<br>
a new function test_eoc_with_timeout to test the eoc flag<br>
with timeout.
@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 "apci3200-private.h"
#include "iomap.h"

/**@def EXPORT_NO_SYMBOLS
* Function in this file are not exported.
*/
EXPORT_NO_SYMBOLS;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
#define __user
#endif


/**@Remark
*
* CJC don't need the offset management like a channel read.
* There is only one CJC on the APCI-3200.
*/

int i_APCI3200_ReadCJCValueFast(struct pci_dev *pdev, unsigned long *value)
{
	/* Configure the CJC Conversion */
	if( outl_cjc(pdev, APCI3200_REG_ACQUISITION_CONFIG, 0x00000400 ) )
		return -EIO;

	/* Start the acquisition */
	if( outl_cjc(pdev, APCI3200_REG_ACQUISITION_CONTROL, 0x00080000) )
		return -EIO;

	/* Wait the end of the conversion (analog to digital) */
	if ( wait_for_eoc (pdev, 0) )
		return -EIO;

	/* Read the digital value of the CJC */
	*value = INPDW (GET_BAR1(pdev) + 28);

	return 0;
}

/** Read the CJC value.
*
* @param [in,out]	pdev	Pointer on the device structure.
* @param [in]		cmd		IOCTL command. The command is <br>
* 							CMD_APCI3200_ReadCJCValue when using the IOCTL funktion.<br>
* 							To call the function in kernel mode, cmd must be 0.
* @param [in,out]	arg	Read1CJCInputChannel_t
*
* @retval 0		No error.
* @retval -EFAULT	Fail to get user parameters.
* @retval -EIO		Timeout.
*/
int do_CMD_APCI3200_ReadCJCValue(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	/* Variable declaration */
	struct Read1CJCInputChannel_t AnalogInputConfig;

	/* no need of locks in this code block (PRIVDATA is not used) */

	/* Get configuration from user mode */
	if ( copy_from_user( &AnalogInputConfig, (struct Read1CJCInputChannel_t __user *)arg, sizeof(struct Read1CJCInputChannel_t) ) )
		return -EFAULT;

	{
		int ret;

		ret = i_APCI3200_SetConvertingTime(pdev, 0, AnalogInputConfig.dw_TimerReloadValue);
		if(ret)
			return ret;

		ret = i_APCI3200_ReadCJCValueFast(pdev, &(AnalogInputConfig.dw_ChannelValue));
		if(ret)
			return ret;
	}

	if ( copy_to_user( (struct Read1CJCInputChannel_t __user *) arg , &AnalogInputConfig, sizeof(struct Read1CJCInputChannel_t) ) )
		return -EFAULT;

	return 0;
}
int do_CMD_APCI3200_ReadCJCValueFast (struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	unsigned long value;
	int ret = i_APCI3200_ReadCJCValueFast(pdev, &value);
	if(ret)
		return ret;
	if ( copy_to_user( (unsigned long __user *) arg , &value, sizeof(unsigned long) ) )
		return -EFAULT;
	return 0;
}

/** Read the CJC calibration gain value.
*
* @param [in,out]	pdev	Pointer on the device structure.
* @param [in]		cmd		IOCTL command. The command is <br>
* 							CMD_APCI3200_ReadCJCCalibrationGainValue when using the IOCTL funktion.<br>
* 							To call the function in kernel mode, cmd must be 0.
* @param [in,out]	arg	Read1CJCInputChannel_t
*
* @retval 0		No error.
* @retval -EFAULT	Fail to get user parameters.
* @retval -EIO		Timeout.
*/
int do_CMD_APCI3200_ReadCJCCalibrationGainValue(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	/* Variable Declaration */
	struct Read1CJCInputChannel_t AnalogInputConfig;

	/* no need of locks in this code block (PRIVDATA is not used) */

	/* Get configuration from user mode */
	if ( copy_from_user( &AnalogInputConfig, (struct Read1CJCInputChannel_t __user *)arg, sizeof(struct Read1CJCInputChannel_t) ) )
		return -EFAULT;

	{
		/* Set the converting time unit */
		if( outl_cjc(pdev, APCI3200_REG_CONVERSION_BASE, AnalogInputConfig.b_ConvertingTimeUnit ) )
			return -EIO;

		/* Set the converting time */
		if( outl_cjc(pdev, APCI3200_REG_CONVERSION_VALUE, AnalogInputConfig.dw_TimerReloadValue ) )
			return -EIO;

		/* Configure the CJC Conversion */
		if( outl_cjc(pdev, APCI3200_REG_ACQUISITION_CONFIG, 0x00000400 ) )
			return -EIO;

		/* Configure the Gain Conversion */
		if( outl_cjc(pdev, APCI3200_REG_READYBIT, 0x00040000 ) )
			return -EIO;

		/* Start the CJC gain acquisition */
		if( outl_cjc(pdev, APCI3200_REG_ACQUISITION_CONTROL, 0x00080000 ) )
			return -EIO;

		/* Wait the end of the conversion (analog to digital) */
		if (wait_for_eoc (pdev, 0))
			return -1;

		/* Read the digital value of the calibration Gain */
		AnalogInputConfig.dw_ChannelValue = INPDW (GET_BAR1(pdev) + 28);
	}
	/* Transfers the value to the user */
	if ( copy_to_user( (struct Read1CJCInputChannel_t __user *) arg , &AnalogInputConfig, sizeof(struct Read1CJCInputChannel_t) ) )
		return -EFAULT;

	return 0;
}

/** Read the CJC calibration offset value.
*
* @param [in,out]	pdev	Pointer on the device structure.
* @param [in]		cmd		IOCTL command. The command is <br>
* 							CMD_APCI3200_ReadCJCCalibrationOffsetValue when using the IOCTL funktion.<br>
* 							To call the function in kernel mode, cmd must be 0.
* @param [in,out]	arg	Read1CJCInputChannel_t
*
* @retval 0		No error.
* @retval -EFAULT	Fail to get user parameters.
* @retval -1		Timeout.
*/
int do_CMD_APCI3200_ReadCJCCalibrationOffsetValue(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	/* Variable Declaration */
	struct Read1CJCInputChannel_t AnalogInputConfig;

	/* no need of locks in this code block (PRIVDATA is not used) */

	/* Get configuration from user mode */
	if ( copy_from_user( &AnalogInputConfig, (struct Read1CJCInputChannel_t __user *)arg, sizeof(struct Read1CJCInputChannel_t) ) )
		return -EFAULT;

	{
		/* Set the converting time unit */
		if( outl_cjc(pdev, APCI3200_REG_CONVERSION_BASE, AnalogInputConfig.b_ConvertingTimeUnit ) )
			return -EIO;

		/* Set the converting time */
		if( outl_cjc(pdev, APCI3200_REG_CONVERSION_VALUE, AnalogInputConfig.dw_TimerReloadValue ) )
			return -EIO;

		/* Configure the CJC Conversion */
		if( outl_cjc(pdev, APCI3200_REG_ACQUISITION_CONFIG, 0x00000400 ) )
			return -EIO;

		/* Configure the Offset Conversion */
		if( outl_cjc(pdev, APCI3200_REG_READYBIT, 0x00020000 ) )
			return -EIO;

		/* Start the CJC offset acquisition */
		if( outl_cjc(pdev, APCI3200_REG_ACQUISITION_CONTROL, 0x00080000 ) )
			return -EIO;

		/* Wait the end of the conversion (analog to digital) */
		if ( wait_for_eoc (pdev, 0) )
			return -1;

		/* Read the digital value of the calibration Offset */
		AnalogInputConfig.dw_ChannelValue = INPDW (GET_BAR1(pdev) + 28);
	}
	/* Transfers the value to the user */
	if ( copy_to_user( (struct Read1CJCInputChannel_t __user *) arg , &AnalogInputConfig, sizeof(struct Read1CJCInputChannel_t) ) )
		return -EFAULT;

	return 0;
}
