/** @file kapi_dig_outputs.c
 
   Contains all functions to set digital outputs 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;
 
//------------------------------------------------------------------------------

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

/** Set all digital outputs of the APCI-1648 on.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param 			PortsState		Function argument. An array of 6 unsigned char that has contain ports states.<br>
 *                          Each index of the array is a port e.g.:<br>
 *                          PortsState [0]: Port 0, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [1]: Port 1, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [2]: Port 2, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [3]: Port 3, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [4]: Port 4, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [5]: Port 5, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *
 * @retval 0		No error. 
 */
int APCI1648_SetAllDigitalOutputsOn(struct pci_dev *pdev, const unsigned char PortsState[6])
{
   	int i = 0;

	/* Test if output memory is used */
    if ( APCI1648_PRIVDATA(pdev)->OutputMemoryStatus )
    {
         /* Copy states to set in the board structure */         	
         for (i=0; i<4; i++)
            APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.SinglePort[i] |= PortsState [APCI1648_PORT0 + i]; 

         for (i=0; i<2; i++)
            APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.SinglePort[i] |= PortsState [APCI1648_PORT4 + i];        	
    } 
    else
    {
         /* Copy states to set in the board structure */         	
         for (i=0; i<4; i++)
            APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.SinglePort[i] = PortsState [APCI1648_PORT0 + i];
         for (i=0; i<2; i++)
            APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.SinglePort[i] = PortsState [APCI1648_PORT4 + i];
    }

	/* Apply new outputs states */
    outl(APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.AllPorts, ((GET_BAR0(pdev) + APCI1648_WRITEREG_1)));
    outl(APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.AllPorts, ((GET_BAR0(pdev) + APCI1648_WRITEREG_2)));
    
	return 0;
}

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

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

/** Set all digital outputs of the APCI-1648 off.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param 			arg		Function argument. An array of 6 unsigned char that has contain ports states.<br>
 *                          Each index of the array is a port e.g.:<br>
 *                          PortsState [0]: Port 0, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [1]: Port 1, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [2]: Port 2, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [3]: Port 3, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [4]: Port 4, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [5]: Port 5, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *
 * @retval 0		No error. 
 * @retval -EPERM	Output memory is not activated.
 */
int APCI1648_SetAllDigitalOutputsOff(struct pci_dev *pdev, const unsigned char PortsState[6])
{
   	int i = 0;
                              
	/* Test if output memory is used */
    if ( !APCI1648_PRIVDATA(pdev)->OutputMemoryStatus )
         return -EPERM;
         
      /* Copy states to set in the board structure */         	
	for (i=0; i<4; i++)
        APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.SinglePort[i] &= (~PortsState [APCI1648_PORT0 + i]);                         
    for (i=0; i<2; i++)
    	APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.SinglePort[i] &= (~PortsState [APCI1648_PORT4 + i]);

	/* Apply new outputs states */
    outl(APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.AllPorts, ((GET_BAR0(pdev) + APCI1648_WRITEREG_1)));
    outl(APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.AllPorts, ((GET_BAR0(pdev) + APCI1648_WRITEREG_2)));      
	
  	return 0;
}

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

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

/** Set the digital output memory on.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param 			arg		Non arg, it can be NULL.
 *
 * @retval 0		No error.
 */
int APCI1648_SetDigitalOutputMemoryOn(struct pci_dev *pdev)
{ 
	/* Get the states of port 0 to 3 */
    APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.AllPorts = inl((GET_BAR0(pdev) + APCI1648_WRITEREG_1));
         
    /* Get the states of port 4 to 5 */
    APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.AllPorts = inl((GET_BAR0(pdev) + APCI1648_WRITEREG_2));         
      
    /* Set the digital output memory flag on */
    APCI1648_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.
 */
int APCI1648_SetDigitalOutputMemoryOff(struct pci_dev *pdev)
{
	/* Set the states of port 0 to 3 */
    APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.AllPorts = 0;
         
    /* Set the states of port 4 to 5 */
    APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.AllPorts = 0;         
      
    /* Set the digital output memory flag off */
    APCI1648_PRIVDATA(pdev)->OutputMemoryStatus = 0;

    return 0;
}

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

/** Get all digital outputs states of the APCI-1648.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param 			arg		Function argument. An array of 6 unsigned char that contain ports states.<br>
 *                          Each index of the array is a port e.g.:<br>
 *                          PortsState [0]: Port 0, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [1]: Port 1, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [2]: Port 2, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [3]: Port 3, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [4]: Port 4, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *                          PortsState [5]: Port 5, is composed of 8 channels. One channel can be 1 (high) or 0 (low).
 *
 * @retval 0		No error. 
 */
int APCI1648_GetAllDigitalOutputsStates(struct pci_dev *pdev, unsigned char PortsState[6])
{
	int i = 0;

	/* Get the states of port 0 to 3 */
	APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.AllPorts = inl((GET_BAR0(pdev) + APCI1648_WRITEREG_1));

	/* Get the states of port 4 to 5 */
	APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.AllPorts = inl((GET_BAR0(pdev) + APCI1648_WRITEREG_2));
	
	/* Copy ports settings to return them to user */
	for (i=0; i<4; i++)
	{
    	PortsState [APCI1648_PORT0 + i] = APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register1.SinglePort[i];
	}
	for (i=0; i<2; i++)         
	{
    	PortsState [APCI1648_PORT4 + i] = APCI1648_PRIVDATA(pdev)->RegisterDigitalOutput.Register2.SinglePort[i];
	}
	return 0;
}
	

