/** @file ana_inputs.c

Contains analog inputs functions, to initialize and read analog values on the APCI-3200.

@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			: 18.07.2005
Author		: Krauth Julien
Description	: Correction on channel 1,2,3 the channel number was not updated.

@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"

/**@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

//#define MARK() printk("%s:%d\n",__FUNCTION__,__LINE__)
#define MARK()


/** Initialise the analog input.
*
* @param [in,out]	pdev	Pointer on the device structure.
* @param [in]		cmd		IOCTL command. The command is <br>
* 							CMD_APCI3200_InitAnalogInputChannel when using the IOCTL funktion.<br>
* 							To call the function in kernel mode, cmd must be 0.
* @param [in]		arg		InitAnalogInputChannel_t
*
* @retval 0		No error.
* @retval -EFAULT	Fail to get user parameters.
* @retval -EINVAL	Incorrect parameter
* @retval -1		Timeout.
*/
int do_CMD_APCI3200_InitAnalogInputChannel(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	struct InitAnalogInputChannel_t AnalogInputConfig;

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

	if( check_channel(AnalogInputConfig.b_Channel) )
		return -EINVAL;
	/* no need of locks in this code block (PRIVDATA is not used) */
	return i_APCI3200_InitAnalogInputChannel(pdev, &AnalogInputConfig);

}

/** Read the specified analog input channel.
*
* @param [in,out]	pdev	Pointer on the device structure.
* @param [in]		cmd		IOCTL command. The command is <br>
* 							CMD_APCI3200_Read1AnalogInputChannel when using the IOCTL funktion.<br>
* 							To call the function in kernel mode, cmd must be 0.
* @param [in,out]	arg	Read1AnalogInputChannel_t
*
* @retval 0		No error.
* @retval -EFAULT	Fail to get user parameters.
* @retval -EINVAL	Incorrect parameter
* @retval -1		Timeout.
*/
int do_CMD_APCI3200_Read1AnalogInputChannel(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	/* Variable declaration */
	struct Read1AnalogInputChannel_t AnalogInputConfig;

	MARK();

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

	if( check_channel(AnalogInputConfig.b_Channel) )
		return -EINVAL;
	/* no need of locks in this code block (PRIVDATA is not used) */
	{
		int ret = i_APCI3200_Read1AnalogInputChannel(pdev, &AnalogInputConfig);
		if(ret)
			return ret;
	}

	/* Transfers the value to the user */
	if ( copy_to_user( (struct Read1AnalogInputChannel_t __user *) arg , &AnalogInputConfig, sizeof(struct Read1AnalogInputChannel_t) ) )
		return -EFAULT;

	return(0);
}

/** Read the calibration gain value on the specified analog input channel.
*
* @param [in,out]	pdev	Pointer on the device structure.
* @param [in]		cmd		IOCTL command. The command is <br>
* 							CMD_APCI3200_ReadCalibrationGainValue when using the IOCTL funktion.<br>
* 							To call the function in kernel mode, cmd must be 0.
* @param [in,out]	arg	Read1AnalogInputChannel_t
*
* @retval 0		No error.
* @retval -EFAULT	Fail to get user parameters / to return user parameters.
* @retval -EINVAL	Incorrect parameter
* @retval -1		Timeout.
*/
int do_CMD_APCI3200_ReadCalibrationGainValue(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{

	/* Variable Declaration */
	struct Read1AnalogInputChannel_t AnalogInputConfig;

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

	if( check_channel(AnalogInputConfig.b_Channel) )
		return -EINVAL;

	/* no need of locks in this code block (PRIVDATA is not used) */
	{
		int ret = i_APCI3200_ReadCalibrationGainValue(pdev, &AnalogInputConfig);
		if(ret)
			return ret;
	}
	/* Transfers the value to the user */
	if ( copy_to_user( (struct Read1AnalogInputChannel_t __user *) arg , &AnalogInputConfig, sizeof(struct Read1AnalogInputChannel_t) ) )
		return -EFAULT;

	return 0;
}

/** Read the calibration offset value on the specified analog input channel.
*
* @param [in,out]	pdev	Pointer on the device structure.
* @param [in]		cmd		IOCTL command. The command is <br>
* 							CMD_APCI3200_ReadCalibrationOffsetValue when using the IOCTL funktion.<br>
* 							To call the function in kernel mode, cmd must be 0.
* @param [in,out]	arg	Read1AnalogInputChannel_t
*
* @retval 0		No error.
* @retval -EFAULT	Fail to get user parameters / to return user parameters.
* @retval -EINVAL	Incorrect parameter
* @retval -1		Timeout.
*/
int do_CMD_APCI3200_ReadCalibrationOffsetValue(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	struct Read1AnalogInputChannel_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 Read1AnalogInputChannel_t __user *)arg, sizeof(struct Read1AnalogInputChannel_t) ) )
		return -EFAULT;

	if( check_channel(AnalogInputConfig.b_Channel) )
		return -EINVAL;

	{
		int ret = i_APCI3200_ReadCalibrationOffsetValue(pdev, &AnalogInputConfig);
		if(ret)
			return ret;
	}

	/* Transfers the value to the user */
	if ( copy_to_user( (struct Read1AnalogInputChannel_t __user *) arg , &AnalogInputConfig, sizeof(struct Read1AnalogInputChannel_t) ) )
		return -EFAULT;

	return 0;
}

/** Read the reference voltage for a given channel
*
* @param [in,out]	pdev	Pointer on the device structure.
* @param [in]		cmd		IOCTL command. The command is <br>
* 							CMD_APCI3200_ReadCalibrationOffsetValue when using the IOCTL funktion.<br>
* 							To call the function in kernel mode, cmd must be 0.
* @param [in,out]	arg	Read1AnalogInputChannel_t
*
* @retval 0		No error.
* @retval -EFAULT	Fail to get user parameters / to return user parameters.
* @retval -EINVAL	Incorrect parameter
* @retval -1		Timeout.
*/
int do_CMD_APCI3200_ReadReferenceVoltage(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	struct ReadReferenceVoltage_t ReadReferenceVoltage;

	if( copy_from_user(&ReadReferenceVoltage, (struct ReadReferenceVoltage_t __user *)arg, sizeof(struct ReadReferenceVoltage_t) ) )
		return -EFAULT;

	{
		int ret = i_APCI3200_ReadReferenceVoltage(pdev, ReadReferenceVoltage.b_Channel, &ReadReferenceVoltage.dw_ReferenceVoltage, &ReadReferenceVoltage.Unit);
		if(ret)
			return ret;
	}

	if( copy_to_user((struct ReadReferenceVoltage_t __user *)arg, &ReadReferenceVoltage, sizeof(struct ReadReferenceVoltage_t) ) )
		return -EFAULT;

	return 0;
}

int do_CMD_APCI3200_SetConvertingTime(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	struct SetConvertingTime_t SetConvertingTime;

	if( copy_from_user(&SetConvertingTime, (struct SetConvertingTime_t __user *)arg, sizeof(struct SetConvertingTime_t) ) )
		return -EFAULT;

	return i_APCI3200_SetConvertingTime(pdev, channel_to_module(SetConvertingTime.b_Channel), SetConvertingTime.dw_TimerReloadValue);
}

int do_CMD_APCI3200_Read1AnalogInputChannelFast (struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	unsigned long channel;
	unsigned long value;
	int ret;

	if( copy_from_user(&channel, (unsigned long __user *)arg, sizeof(unsigned long) ) )
		return -EFAULT;

	ret = i_APCI3200_Read1AnalogInputChannelFast (pdev, channel, &value);
	if(ret)
		return ret;

	if( copy_to_user((unsigned long __user *)arg, &value, sizeof(unsigned long) ) )
		return -EFAULT;

	return 0;
}

int do_CMD_APCI3200_ReadCalibrationOffsetValueFast (struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	unsigned long channel;
	unsigned long value;
	int ret;

	if( copy_from_user(&channel, (unsigned long __user *)arg, sizeof(unsigned long) ) )
		return -EFAULT;

	ret = i_APCI3200_ReadCalibrationOffsetValueFast (pdev, channel, &value);
	if(ret)
		return ret;

	if( copy_to_user((unsigned long __user *)arg, &value, sizeof(unsigned long) ) )
		return -EFAULT;

	return 0;
}

int do_CMD_APCI3200_ReadCalibrationGainValueFast (struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	unsigned long channel;
	unsigned long value;
	int ret;

	if( copy_from_user(&channel, (unsigned long __user *)arg, sizeof(unsigned long) ) )
		return -EFAULT;

	ret = i_APCI3200_ReadCalibrationGainValueFast (pdev, channel, &value);
	if(ret)
		return ret;

	if( copy_to_user((unsigned long __user *)arg, &value, sizeof(unsigned long) ) )
		return -EFAULT;

	return 0;
}

/** Set / Reset the diagnostic mode.
 *
 * This function permits to enable disable diagnostic test.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [in]		cmd		IOCTL command. The command is <br>
 * 							CMD_APCI3200_SetDiagnosticMode when using the IOCTL funktion.<br>
 * 							To call the function in kernel mode, cmd must be 0.
 * @param [in]		arg	mode:
 *  					- APCI3200_DIAGNOSTIC_NONE:				Disable diagnostic test.
 * 						- APCI3200_DIAGNOSTIC_OPEN_CONNECTION:	Open connection test.
 * @param [in]		arg channel: The channel to test (single 0 - 15, differential 0 - 7).
 *
 * @retval 0		No error.
 * @retval -EINVAL	Incorrect parameter.
 * @retval -EFAULT	Fail to get user parameters.
 */
int do_CMD_APCI3200_SetDiagnosticMode(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	unsigned char value[2] = {0,0};

	if( copy_from_user(value, (unsigned char __user *)arg, sizeof(value) ) )
		return -EFAULT;

	return (i_APCI3200_SetDiagnosticMode (pdev, (unsigned char) value[0], (unsigned char) value[1]));
}

/** Get the diagnostic mode.
 *
 * This function permits to get the configured diagnostic test.

 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [in]		cmd		IOCTL command. The command is <br>
 * 							CMD_APCI3200_SetDiagnosticMode when using the IOCTL funktion.<br>
 * 							To call the function in kernel mode, cmd must be 0.
 * @param [in]		arg channel: The channel to test (single 0 - 15, differential 0 - 7).
 * @param [out]		arg	mode:
 *  					- APCI3200_DIAGNOSTIC_NONE:				Disable diagnostic test.
 * 						- APCI3200_DIAGNOSTIC_OPEN_CONNECTION:	Open connection test.
 *
 * @retval -EINVAL	Incorrect parameter.
 * @retval -EFAULT	Fail to return user parameters.
 */
int do_CMD_APCI3200_GetDiagnosticMode(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	unsigned char mode = i_APCI3200_GetDiagnosticMode (pdev, (unsigned char) arg);

	/* Returns the modified input value to the user */
	if ( copy_to_user( (unsigned char __user *) arg , &mode, sizeof(unsigned char) ) )
		return -EFAULT;

	return (0);
}

