/** @file dig_init.c
 
   Contains all functions to initialize digital inputs of the APCI-1696.
 
   @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 "apci1696-private.h"
#include <apci1696-kapi.h>

/**@def EXPORT_NO_SYMBOLS
 * Function in this file are not exported.
 */
EXPORT_NO_SYMBOLS;

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

/** Initialize all digital ports of the APCI-1696.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param 			PortsSetting		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 [11]: Port 11 (0: Input direction / 1: Output direction)
 *
 * @retval 0		No error. 
 * @retval -EINVAL	Port settings are incorrect.
 */
int APCI1696_InitAllDigitalPorts(struct pci_dev *pdev, const unsigned char PortsSetting[APCI1696_PORT_NUMBER])
{
	// TODO
	/* Legal initializations values are 0 or 1 */
	int i;
	for (i=0; i<APCI1696_PORT_NUMBER; i++)
	{
		switch(PortsSetting[i])
		{
			case 0:
			case 1:
				break;
			default:
				return -EINVAL;	
		}        	  	
	}
	/* register 1 : ports 0 - 3 */  
    APCI1696_PRIVDATA(pdev)->RegisterSetting.Register1.AllPorts = ((uint8_t)(PortsSetting [APCI1696_PORT0] * 0xFF) |
                                                                    ((uint8_t)(PortsSetting [APCI1696_PORT1] * 0xFF) << 8) |
                                                                    ((uint8_t)(PortsSetting [APCI1696_PORT2] * 0xFF) << 16) |
                                                                    ((uint8_t)(PortsSetting [APCI1696_PORT3] * 0xFF) << 24));
  	/* register 2 : ports 4 - 7 */
	APCI1696_PRIVDATA(pdev)->RegisterSetting.Register2.AllPorts = ((uint8_t)(PortsSetting [APCI1696_PORT4] * 0xFF) 
																| ((uint8_t)(PortsSetting [APCI1696_PORT5] * 0xFF) << 8) 
																| ((uint8_t)(PortsSetting [APCI1696_PORT6] * 0xFF) << 16)
																| ((uint8_t)(PortsSetting [APCI1696_PORT7] * 0xFF) << 24)
																);
  	/* register 3 : ports 8 - 11 */
	APCI1696_PRIVDATA(pdev)->RegisterSetting.Register3.AllPorts = ((uint8_t)(PortsSetting [APCI1696_PORT8] * 0xFF) 
																| ((uint8_t)(PortsSetting [APCI1696_PORT9] * 0xFF) << 8) 
																| ((uint8_t)(PortsSetting [APCI1696_PORT10] * 0xFF) << 16)
																| ((uint8_t)(PortsSetting [APCI1696_PORT11] * 0xFF) << 24)
																);

    /* Flush ports 0 - 3 */ 
	outl(APCI1696_PRIVDATA(pdev)->RegisterSetting.Register1.AllPorts, (GET_BAR0(pdev) + APCI1696_CMDREG_1)); 
	/* Flush ports 4 - 7 */ 
	outl(APCI1696_PRIVDATA(pdev)->RegisterSetting.Register2.AllPorts, (GET_BAR0(pdev) + APCI1696_CMDREG_2));
	/* Flush ports 8 - 11 */ 
	outl(APCI1696_PRIVDATA(pdev)->RegisterSetting.Register3.AllPorts, (GET_BAR0(pdev) + APCI1696_CMDREG_3));

  	return 0;	
}

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

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

/** Get all digital ports settings of the APCI-1696.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param 			PortsSetting		Function argument. An array of 12 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 [11]: Port 11 (0: Input direction / 1: Output direction)
 *
 * @retval 0		No error. 
 */
int APCI1696_GetAllDigitalPortsSetting(struct pci_dev *pdev, unsigned char PortsSetting[APCI1696_PORT_NUMBER])
{

	/* read register 1 : ports 0 - 3 */      
	APCI1696_PRIVDATA(pdev)->RegisterSetting.Register1.AllPorts = inl((GET_BAR0(pdev) + APCI1696_CMDREG_1));
	
	/* read register 2 : ports 4 - 7 */      
	APCI1696_PRIVDATA(pdev)->RegisterSetting.Register2.AllPorts = inl((GET_BAR0(pdev) + APCI1696_CMDREG_2));

	/* read register 3 : ports 8 - 11 */      
	APCI1696_PRIVDATA(pdev)->RegisterSetting.Register3.AllPorts = inl((GET_BAR0(pdev) + APCI1696_CMDREG_3));

	/* to user */
	{
		int i;
		for (i=0; i<4; i++)
			PortsSetting [APCI1696_PORT0 + i] = APCI1696_PRIVDATA(pdev)->RegisterSetting.Register1.SinglePort[i] & 0x1;
		for (i=0; i<4; i++)
			PortsSetting [APCI1696_PORT4 + i] = APCI1696_PRIVDATA(pdev)->RegisterSetting.Register2.SinglePort[i] & 0x1;
		for (i=0; i<4; i++)
			PortsSetting [APCI1696_PORT8 + i] = APCI1696_PRIVDATA(pdev)->RegisterSetting.Register3.SinglePort[i] & 0x1;
	}
	return 0;
}

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

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

/** Initialize one port of the APCI-1696.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param 			arg		DigitalPortsArg_t
 *
 * @retval 0		No error. 
 * @retval -EINVAL	The port number or the initialization value is incorrect.
 */
int APCI1696_InitDigitalPort(struct pci_dev *pdev, struct DigitalPortsArg_t * arg)
{	  
	
	/* Legal initializations values are 0 or 1 */
	switch(arg->Value)
	{
		case 0:
		case 1:
			break;
		default:
			return -EINVAL;	
	}
	switch(arg->Port)
	{
		case 0 ... 3:
			APCI1696_PRIVDATA(pdev)->RegisterSetting.Register1.SinglePort[arg->Port] = arg->Value;
			outl(APCI1696_PRIVDATA(pdev)->RegisterSetting.Register1.AllPorts, ((GET_BAR0(pdev) + APCI1696_CMDREG_1)));
			break;
		case 4 ... 7:
			APCI1696_PRIVDATA(pdev)->RegisterSetting.Register2.SinglePort[(arg->Port)-4] = arg->Value;
			outl(APCI1696_PRIVDATA(pdev)->RegisterSetting.Register2.AllPorts, ((GET_BAR0(pdev) + APCI1696_CMDREG_2)));
			break;
		case 8 ... 11:
			APCI1696_PRIVDATA(pdev)->RegisterSetting.Register3.SinglePort[(arg->Port)-8] = arg->Value;
			outl(APCI1696_PRIVDATA(pdev)->RegisterSetting.Register3.AllPorts, ((GET_BAR0(pdev) + APCI1696_CMDREG_3)));
			break;
		default: /* Legal port value is 0 to APCI1696_PORT_NUMBER-1 */
			return -EINVAL;
	}
	
    return 0;
}

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

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

/** Get one port initialization of the APCI-1696.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 * @param 			arg		DigitalPortsArg_t
 *
 * @retval 0		No error. 
 * @retval -EINVAL	The port number is falls.
 */
int APCI1696_GetDigitalPortSetting(struct pci_dev *pdev, struct DigitalPortsArg_t * arg)
{      
	/* Legal port value is 0 to APCI1696_PORT_NUMBER-1 */
	switch(arg->Port)
	{
		case 0 ... 3:
			APCI1696_PRIVDATA(pdev)->RegisterSetting.Register1.AllPorts = inl((GET_BAR0(pdev) + APCI1696_CMDREG_1));
	        arg->Value = APCI1696_PRIVDATA(pdev)->RegisterSetting.Register1.SinglePort[arg->Port];
			break;
		case 4 ... 7:
			APCI1696_PRIVDATA(pdev)->RegisterSetting.Register2.AllPorts = inl((GET_BAR0(pdev) + APCI1696_CMDREG_2));
	        arg->Value = APCI1696_PRIVDATA(pdev)->RegisterSetting.Register2.SinglePort[(arg->Port)-4];
			break;
		case 8 ... 11:
			APCI1696_PRIVDATA(pdev)->RegisterSetting.Register3.AllPorts = inl((GET_BAR0(pdev) + APCI1696_CMDREG_3));
	        arg->Value = APCI1696_PRIVDATA(pdev)->RegisterSetting.Register3.SinglePort[(arg->Port)-8];
			break;
		default:
			return -EINVAL;
	}
	return 0;
}
