/** @file dig_outputs.c
 
   Contains all functions to set digital outputs of the APCIE-2200.
 
   @par CREATION  
   @author Krauth Julien
   @date   07.01.09
   
   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim   
    
   @par LICENCE
   @verbatim
   Copyright (C) 2009  ADDI-DATA GmbH for the source code of this module.
        
        ADDI-DATA GmbH
        Airpark Business Center
        Airport Boulevard B210
        77836 Rheinm�nster
        Germany
        Tel: +49(0)7229/1847-0
        Fax: +49(0)7229/1847-200
        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 <apcie2200-kapi.h>
#include "apcie2200-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


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

/** Set all digital outputs of the APCIE-2200 on.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [in]		arg		Function argument. An unsigned char that has contain port state to set.
 *
 * @retval 0		No error. 
 * @retval -EFAULT	Can't return parameters.
 * @retval -EINVAL	Value to set is too high (check the number of digital outputs of your board).
 */
int APCIE2200_Set16DigitalOutputsOn(struct pci_dev *pdev, uint32_t arg)
{
	switch (APCIE2200_PRIVDATA(pdev)->nbrdigitalOutput)
	{
		case 0:
			/* No digital output available */
			return -EINVAL;
		break;

		case 8:
			if (arg > 0xFF)
			{
				/* Only 8 digital outputs are available */
				return -EINVAL;
			}
		break;

		case 16:
			if (arg > 0xFFFF)
			{
				/* Only 16 digital outputs are available */
				return -EINVAL;
			}
		break;
	}

	/* Test if output memory is used */
  	if ( APCIE2200_PRIVDATA(pdev)->OutputMemoryStatus )
    {
        /* Copy state to set in the board structure */         	
        APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput |= arg;
    } 
  	else
    {
        /* Copy state to set in the board structure */         	
        APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput = arg;
    }

	/* Apply new output state */
	outl(APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput, ((GET_BAR3(pdev) + APCIE2200_DIGITAL_OUTPUT_REG)));
 
	return 0;
}

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

/** Set all digital outputs of the APCIE-2200 off.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [in]		cmd		IOCTL command. The command is <br>
 * 							CMD_APCIE2200_Set8DigitalOutputsOn when using the IOCTL funktion.<br>
 * 							To call the function in kernel mode, cmd must be 0.
 * @param [in]		arg		Function argument. An unsigned char that has contain port state to reset.
 *
 * @retval 0		No error. 
 * @retval -EPERM	Output memory is not activated.
 * @retval -EFAULT	Can't return parameters.
 * @retval -EINVAL	Value to set is too high (check the number of digital outputs of your board).
 */
int APCIE2200_Set16DigitalOutputsOff(struct pci_dev *pdev, uint32_t arg)
{
	/* Test the value to reset */
	switch (APCIE2200_PRIVDATA(pdev)->nbrdigitalOutput)
	{
		case 0:
			/* No digital output available */
			return -EINVAL;
		break;

		case 8:
			if (arg > 0xFF)
			{
				/* Only 8 digital outputs are available */
				return -EINVAL;
			}
		break;

		case 16:
			if (arg > 0xFFFF)
			{
				/* Only 16 digital outputs are available */
				return -EINVAL;
			}
		break;
	}

	/* Test if output memory is used */
	if ( !APCIE2200_PRIVDATA(pdev)->OutputMemoryStatus )
	{
    	return -EPERM;
	}
	/* Copy state to set in the board structure */         	
	APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput &= (~arg);

	/* Apply new output state */
	outl(APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput, ((GET_BAR3(pdev) + APCIE2200_DIGITAL_OUTPUT_REG)));

	return 0;
}

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

/** Set the digital output memory on.
 *
 * @param [in,out]	pdev	Pointer on the device structure. *
 * @retval 0		No error.
 * @retval -ENXIO	No digital outputs.
 */
int APCIE2200_SetDigitalOutputMemoryOn(struct pci_dev *pdev)
{
	if (APCIE2200_PRIVDATA(pdev)->nbrdigitalOutput == 0)
		return -ENXIO;

	/* Get the state of port 0 */
	APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput = inl((GET_BAR3(pdev) + APCIE2200_DIGITAL_OUTPUT_REG));
	             
	/* Set the digital output memory flag on */
	APCIE2200_PRIVDATA(pdev)->OutputMemoryStatus = 1;

    return 0;
}

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

/** Set the digital output memory off.
 *
 * @param [in,out]	pdev	Pointer on the device structure.

 * @retval 0		No error.
 * @retval -ENXIO	No digital outputs.
 */
int APCIE2200_SetDigitalOutputMemoryOff(struct pci_dev *pdev)
{
	if (APCIE2200_PRIVDATA(pdev)->nbrdigitalOutput == 0)
		return -ENXIO;

	/* Set the state of port 0 */
    APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput = 0;
      
    /* Set the digital output memory flag off */
    APCIE2200_PRIVDATA(pdev)->OutputMemoryStatus = 0;

    return 0;
}

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

/** Get all digital outputs states of the APCIE-2200.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [out]		arg		Function argument. An unsigned char that contain port state.
 *
 * @retval 0		No error. 
 * @retval -EFAULT	Can't return parameters.
 * @retval -ENXIO	No digital outputs.
 */
int APCIE2200_Get16DigitalOutputStatus(struct pci_dev *pdev, uint32_t * PortState)
{
	if (APCIE2200_PRIVDATA(pdev)->nbrdigitalOutput == 0)
		return -ENXIO;

	/* Get the state of port 0 */
	APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput = inl((GET_BAR3(pdev) + APCIE2200_DIGITAL_OUTPUT_REG));
		  
	*PortState = APCIE2200_PRIVDATA(pdev)->RegisterDigitalOutput;

	return 0;
}

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

int APCIE2200_GetNumberOfDigitalOutputs (struct pci_dev *pdev)
{
	return (APCIE2200_PRIVDATA(pdev)->nbrdigitalOutput);
}
	
//------------------------------------------------------------------------------

