/** @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 <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
	#include <linux/config.h>
#else
	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
		#include <linux/autoconf.h>
	#else
		#include <generated/autoconf.h>
	#endif
#endif

#include <apcie1564-kapi.h>
#include "apcie1564-private.h"

/** flush internal output register representation to board */
static inline void FLUSH_OUTPUT(struct pci_dev * pdev)
{
	outl ( APCIE1564_PRIVDATA(pdev)->DigitalOutputRegister, GET_BAR3(pdev) + APCIE1564_DIGITAL_OUTPUT_REG);
}

//------------------------------------------------------------------------------
int APCIE1564_Read32DigitalOutput(struct pci_dev *pdev, uint32_t* output_value)
{
    *output_value = inl(GET_BAR3(pdev)+APCIE1564_DIGITAL_OUTPUT_REG);
    return 0;
}

//------------------------------------------------------------------------------------------------------
int do_CMD_APCIE1564_Read32DigitalOutput(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
    uint32_t output_value = 0;
    if ( APCIE1564_Read32DigitalOutput(pdev, &output_value) )
    {
       return -EIO;
    }

    /* returns value to the user */
    if ( copy_to_user( (uint32_t __user *) arg, (uint32_t*) &output_value, sizeof(output_value) ) )
       return -EFAULT;

    return 0;
}

//------------------------------------------------------------------------------
int APCIE1564_Set32DigitalOutputOn(struct pci_dev *pdev, uint32_t arg)
{
	unsigned long irqstate;

	APCIE1564_LOCK(pdev,&irqstate);
	{
		if(APCIE1564_PRIVDATA(pdev)->OutputMemoryState == APCIE1564_ENABLE)
		{
			APCIE1564_PRIVDATA(pdev)->DigitalOutputRegister |= arg;
		}
		else
		{
			APCIE1564_PRIVDATA(pdev)->DigitalOutputRegister = arg;
		}

		FLUSH_OUTPUT(pdev);
	}
	APCIE1564_UNLOCK(pdev,irqstate);

	return 0;
}

//------------------------------------------------------------------------------
int do_CMD_APCIE1564_Set32DigitalOutputOn(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	int ret;

	ret = APCIE1564_Set32DigitalOutputOn(pdev, (uint32_t)arg);

	return ret;
}
//------------------------------------------------------------------------------
int APCIE1564_Set32DigitalOutputOff(struct pci_dev *pdev, uint32_t arg)
{
	unsigned long irqstate;
	APCIE1564_LOCK(pdev,&irqstate);
	{
		if(APCIE1564_PRIVDATA(pdev)->OutputMemoryState != APCIE1564_ENABLE)
		{
			APCIE1564_UNLOCK(pdev,irqstate);
			return -EINVAL;
		}

		APCIE1564_PRIVDATA(pdev)->DigitalOutputRegister &= (0xFFFFFFFF - arg);

		FLUSH_OUTPUT(pdev);
	}
	APCIE1564_UNLOCK(pdev,irqstate);
	return 0;

}
//------------------------------------------------------------------------------
int do_CMD_APCIE1564_Set32DigitalOutputOff(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	int ret;

	ret = APCIE1564_Set32DigitalOutputOff(pdev,(uint32_t)arg);

	return ret;

}
//------------------------------------------------------------------------------
int APCIE1564_SetOutputMemoryOn(struct pci_dev *pdev)
{
	unsigned long irqstate;
	APCIE1564_LOCK(pdev,&irqstate);
	{
		APCIE1564_PRIVDATA(pdev)->OutputMemoryState = APCIE1564_ENABLE;
	}
	APCIE1564_UNLOCK(pdev,irqstate);
	return 0;
}
//------------------------------------------------------------------------------
int do_CMD_APCIE1564_SetOutputMemoryOn(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	int ret;

	ret = APCIE1564_SetOutputMemoryOn(pdev);

	return ret;
}
//------------------------------------------------------------------------------
int APCIE1564_SetOutputMemoryOff(struct pci_dev *pdev)
{
	unsigned long irqstate;
	APCIE1564_LOCK(pdev,&irqstate);
	{
		APCIE1564_PRIVDATA(pdev)->OutputMemoryState = APCIE1564_DISABLE;
	}
	APCIE1564_UNLOCK(pdev,irqstate);
	return 0;
}
//------------------------------------------------------------------------------
int do_CMD_APCIE1564_SetOutputMemoryOff(struct pci_dev *pdev, unsigned int cmd, unsigned long arg)
{
	int ret;

	ret = APCIE1564_SetOutputMemoryOff(pdev);

	return ret;
}
