/** @file dig_init.c
 
   Contains all functions to initialize digital inputs of the APCI-1648.
 
   @par CREATION  
   @author Krauth Julien
   @date   10.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			:
   Author		: 
   Description	: 
   @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 "apci1648-private.h"
#include <apci1648-kapi.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

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

/** Initialize all digital ports of the APCI-1648.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [in]		cmd		IOCTL command. The command is <br>
 * 							CMD_APCI1648_InitAllDigitalPorts when using the IOCTL funktion.<br>
 * 							To call the function in kernel mode, cmd must be 0.
 * @param 			arg		Function argument. An array of 6 unsigned char that has to be initialized as following.<br>
 *                          Each index of the array is a port e.g.:<br>
 *                          PortsSetting [0]: Port 0 (0: Input direction / 1: Output direction)
 *                          PortsSetting [1]: Port 1 (0: Input direction / 1: Output direction)
 *                          PortsSetting [2]: Port 2 (0: Input direction / 1: Output direction)
 *                          PortsSetting [3]: Port 3 (0: Input direction / 1: Output direction)
 *                          PortsSetting [4]: Port 4 (0: Input direction / 1: Output direction)
 *                          PortsSetting [5]: Port 5 (0: Input direction / 1: Output direction)
 *
 * @retval 0		No error. 
 * @retval -EFAULT	Bad address.
 * @retval -EINVAL	Port settings are incorrect.
 * @retval -ERESTARTSYS	Call has been interrupted while trying to get exclusive access to the board. 
 */
int do_CMD_APCI1648_InitAllDigitalPorts(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	unsigned char PortsSetting[APCI1648_PORT_NUMBER]; /**< Ports initialization type:<br>
                                       - 0: Input direction<br>
                                       - 1: Output direction*/
	int ret = 0;                                       
	unsigned long irqstate;
	/* Get initialization parameters */
	if ( copy_from_user(PortsSetting, (unsigned char __user *)arg, sizeof(PortsSetting) ) )
    	return -EFAULT;

	if (APCI1648_LOCK(pdev,&irqstate))
  		return -ERESTARTSYS;
	{
		ret = APCI1648_InitAllDigitalPorts(pdev, PortsSetting); 
	}
	APCI1648_UNLOCK(pdev,irqstate);
  	return ret;
}

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

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

/** Get all digital ports settings of the APCI-1648.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [in]		cmd		IOCTL command. The command is <br>
 * 							CMD_APCI1648_GetAllDigitalPortsSetting when using the IOCTL funktion.<br>
 * 							To call the function in kernel mode, cmd must be 0.
 * @param 			arg		Function argument. An array of 6 unsigned char that will contain ports settings.<br>
 *                          Each index of the array is a port e.g.:<br>
 *                          PortsSetting [0]: Port 0 (0: Input direction / 1: Output direction)
 *                          PortsSetting [1]: Port 1 (0: Input direction / 1: Output direction)
 *                          PortsSetting [2]: Port 2 (0: Input direction / 1: Output direction)
 *                          PortsSetting [3]: Port 3 (0: Input direction / 1: Output direction)
 *                          PortsSetting [4]: Port 4 (0: Input direction / 1: Output direction)
 *                          PortsSetting [5]: Port 5 (0: Input direction / 1: Output direction)
 *
 * @retval 0		No error. 
 * @retval -EFAULT	Bad address.
 * @retval -ERESTARTSYS	Call has been interrupted while trying to get exclusive access to the board. 
 */
int do_CMD_APCI1648_GetAllDigitalPortsSetting(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	unsigned char PortsSetting[APCI1648_PORT_NUMBER]; /**< Ports initialization type:<br>
	                                       - 0: Input direction<br>
	                                       - 1: Output direction*/
	int ret = 0;
	unsigned long irqstate;
	
	if (APCI1648_LOCK(pdev,&irqstate))
  		return -ERESTARTSYS;
	{
		ret = APCI1648_GetAllDigitalPortsSetting(pdev, PortsSetting);
	}
	APCI1648_UNLOCK(pdev,irqstate);

	if(ret)
		return ret;

	/* Returns ports configurations to the user */
	if ( copy_to_user((unsigned char __user *) arg, PortsSetting, sizeof(PortsSetting) ) ) 
		return -EFAULT;
		
	return 0;
}

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

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

/** Initialize one port of the APCI-1648.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [in]		cmd		IOCTL command. The command is <br>
 * 							CMD_APCI1648_InitDigitalPort when using the IOCTL funktion.<br>
 * 							To call the function in kernel mode, cmd must be 0.
 * @param 			arg		DigitalPortsArg_t
 *
 * @retval 0		No error. 
 * @retval -EFAULT	Bad address.
 * @retval -EINVAL	The port number or the initialization value is incorrect.
 * @retval -ERESTARTSYS	Call has been interrupted while trying to get exclusive access to the board. 
 */
int do_CMD_APCI1648_InitDigitalPort(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	struct DigitalPortsArg_t Arg;
	int ret;
	unsigned long irqstate;

	/* Get parameters */
	if ( copy_from_user(&Arg, (struct DigitalPortsArg_t __user *)arg, sizeof(struct DigitalPortsArg_t)) )
		return -EFAULT; 
    
	if (APCI1648_LOCK(pdev,&irqstate))
  		return -ERESTARTSYS;
	{
		ret = APCI1648_InitDigitalPort(pdev, &Arg);
	}
	APCI1648_UNLOCK(pdev,irqstate);
	
	return ret;
}

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

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

/** Get one port initialization of the APCI-1648.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [in]		cmd		IOCTL command. The command is <br>
 * 							CMD_APCI1648_GetDigitalPortSetting when using the IOCTL funktion.<br>
 * 							To call the function in kernel mode, cmd must be 0.
 * @param 			arg		DigitalPortsArg_t
 *
 * @retval 0		No error. 
 * @retval -EFAULT	Bad address.
 * @retval -EINVAL	The port number is incorrect.
 * @retval -ERESTARTSYS	Call has been interrupted while trying to get exclusive access to the board. 
 */
int do_CMD_APCI1648_GetDigitalPortSetting(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	struct DigitalPortsArg_t Arg;
	int ret;
	unsigned long irqstate;
	
	/* Get parameters */
	if (copy_from_user(&Arg,(struct DigitalPortsArg_t __user *)arg, sizeof(struct DigitalPortsArg_t) ) )
		return -EFAULT;  		         

	if (APCI1648_LOCK(pdev,&irqstate))
  		return -ERESTARTSYS;
	{
		ret = APCI1648_GetDigitalPortSetting(pdev, &Arg);
	}
	APCI1648_UNLOCK(pdev,irqstate);

	if(ret)
		return ret;

    /* Returns port configuration to the user */
    if ( copy_to_user((struct DigitalPortsArg_t __user *) arg , (uint32_t*) &Arg, sizeof(struct DigitalPortsArg_t)) )
	{
		return -EFAULT; 
	}
    	
	return 0;
}
