/** @file dig_inputs.c
 
   Contains all functions to read digital inputs of the APCIE-1532.
 
   @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 <apcie1532-kapi.h>
#include "apcie1532-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

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

/** Read all digital inputs of the APCIE-1532.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param [out]		arg		Port state (0 to 65535).
 *
 * @retval 0		No error. 
 * @retval -EFAULT	Can't return parameters.
 */
int APCIE1532_Read16DigitalInputs(struct pci_dev *pdev, uint32_t * PortState)
{
	/* no need to lock since no private data are accessed */

	/* Get the state of port 0 */
	*PortState = (unsigned int) (inl((GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_REG)) & 0xFFFF);

	return 0;
}

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

int APCIE1532_InitAndStartDigitalInputInterrupt (struct pci_dev *pdev, int InterruptLogic, uint32_t InterruptMaskMode1,uint32_t InterruptMaskMode2)
{
	/* check parameters */
	
	/* InterruptLogic must be either 0 or 1 */
	switch(InterruptLogic)
	{
		case 0:
		case 1:
			break;
		default:
			return -EINVAL; 
	}
	
	/* only bits D1 to D15 are legal for mode 1 */
	if ( InterruptMaskMode1 & (~0x0000FFFE) )
	{
		return -EINVAL;
	}
	
	/* only bits D1 to D15 are legal for mode 2 */
	if ( InterruptMaskMode2 & (~0x0000FFFE) )
	{
		return -EINVAL;
	}
	
	/* initialise all registers */
	outl ( 0x0 , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_MODUS1_REG);
	outl ( 0x0 , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_MODUS2_REG);
	outl ( 0x0 , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_LOGIC_REG);
	
	/* write mode 1 */
	outl ( (InterruptMaskMode1) , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_MODUS1_REG);
	
	/* write mode 2 */
	outl ( (InterruptMaskMode2) , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_MODUS2_REG);
	
	/* write compare logic */
	
	switch(InterruptLogic)
	{
		case 0: /* OR */
			outl ( 0x4 , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_LOGIC_REG);
			break;
		case 1: /* AND */
			outl ( 0x6 , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_LOGIC_REG);
			break;
		default: /* should not happen, right ? */
			break;
	}
	/* from now on, interrupt is enabled */
	
	return 0;
}

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

int APCIE1532_ClearAndStopDigitalInputInterrupt (struct pci_dev *pdev)
{
	/* re-initialise all registers */
	outl ( 0x0 , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_MODUS1_REG);
	outl ( 0x0 , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_MODUS2_REG);
	outl ( 0x0 , GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_LOGIC_REG);
	
	/* from now on, interrupt is disabled */
	return 0;
}

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

int APCIE1532_GetDigitalInputInterruptConfig (struct pci_dev *pdev, int * Enabled, int * InterruptLogic, uint32_t * InterruptMaskMode1, uint32_t * InterruptMaskMode2)
{
	*Enabled = (inl ( GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_LOGIC_REG) >> 2) & 0x1;
	*InterruptLogic = (inl ( GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_LOGIC_REG) >> 1) & 0x1;
	*InterruptMaskMode1 = inl ( GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_MODUS1_REG);
	*InterruptMaskMode2 = inl ( GET_BAR3(pdev) + APCIE1532_DIGITAL_INPUT_INTERRUPT_MODUS2_REG);
	return 0;
}

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