/** @file diagnostic-kapi.c

   Contains diagnostic functions.

   @par CREATION
   @author Rose Jordan
   @date   20.09.2010

   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @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 "apci3701-private.h"

EXPORT_SYMBOL(i_APCI3701_PrimaryTransducerEnableDisablePrimaryShortCircuitInterrupt);
EXPORT_SYMBOL(i_APCI3701_PrimaryTransducerEnableDisablePrimaryOpenInputTest);
EXPORT_SYMBOL(i_APCI3701_PrimaryTransducerRearmPrimaryOpenShortCircuitTest);
EXPORT_SYMBOL(i_APCI3701_PrimaryTransducerEnableDisableSecondaryShortCircuitTest);
EXPORT_SYMBOL(i_APCI3701_PrimaryTransducerEnableDisableSecondaryOpenCircuitTest);

/*
 * Enable or disable the interrupt when we detect a short circuit.
 * When a short circuit will be detected, if b_interrupt_flag ==1, it will generate an interruption that can
 * be catched in the interrupt routine
 * @Params in:
 * @param [in] pdev                	: The device for which we want to enable or disable the interruption
 * @param [in] b_interrupt_flag			: 0 for disable, 1 for enable
 * @retval
 * 	1: board handle given in parameter is wrong
 */
int i_APCI3701_PrimaryTransducerEnableDisablePrimaryShortCircuitInterrupt( struct pci_dev *pdev, BYTE b_interrupt_flag )
{
	DWORD dw_previous = 0;
	DWORD dw_set_mask = 0;
	DWORD dw_reset_mask = 0;

	if ( ! pdev )
		return 1;

	// Compute the mask
	dw_set_mask = (DWORD) ( ((DWORD)b_interrupt_flag) << 7 ) ;

	// Compute the reset mask
	dw_reset_mask = 0x80 & ( ~ (DWORD)(b_interrupt_flag << 7) );

	// Get and save the previous value in the register
	INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, &dw_previous);

	// Compute the new value to be written
	dw_previous = ( dw_previous & ( 0xFFFFFFFFUL - dw_reset_mask )) | dw_set_mask;

	// Write it
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, dw_previous );

	// Change the status
	APCI3701_PRIVDATA(pdev)->b_diagnostic_short_circuit_interrupt = b_interrupt_flag;

	return 0;
}

/*
 * Enable or disable the primary open input test
 * Must be done before testing if the primary is in open circuit
 * @Params in:
 * @param [in] pdev                	: The device for which we want to enable or disable the interruption
 * @param [in] b_flag				: 0 for disable, 1 for enable
 * @retval
 * 	1: board handle given in parameter is wrong
 */
int i_APCI3701_PrimaryTransducerEnableDisablePrimaryOpenInputTest( struct pci_dev *pdev, BYTE b_flag )
{
	DWORD dw_previous = 0;
	DWORD dw_set_mask = 0;
	DWORD dw_reset_mask = 0;
	int i;

	if ( ! pdev )
		return 1;

	// Compute the mask
	dw_set_mask = (DWORD) ( ((DWORD)b_flag) << 2 ) ;

	// Compute the reset mask
	dw_reset_mask = 0x4 & ( ~ (DWORD)(b_flag << 2) );

	// Get and save the previous value in the register
	INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, &dw_previous);

	// Compute the new value to be written
	dw_previous = ( dw_previous & ( 0xFFFFFFFFUL - dw_reset_mask )) | dw_set_mask;

	// Write it
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, dw_previous);
	//printk("Enable disable open input : %x \n", dw_previous);

	// Change the board status
	APCI3701_PRIVDATA(pdev)->b_open_circuit_primary_enable = b_flag;

	// No we have to wait until the bit is really taken in account by the board
	// THE FOLLOWING ALGO HAS TO BE CHANGED
	for ( i = 0; i < APCI3701_ITER_TIMEOUT; i++ )
	{
		INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, &dw_previous);
	}

	return 0;
}

/*
 * Rearm the primary short circuit
 * When a short circuit is detected, the card doesn't generate data anymore
 * We have to rearm the system to continue
 * @retval
 * 	1: board handle given in parameter is wrong
 */
int i_APCI3701_PrimaryTransducerRearmPrimaryOpenShortCircuitTest( struct pci_dev* pdev )
{
	DWORD dw_previous = 0;
	DWORD dw_set_mask = 0;

	if ( ! pdev )
		return 1;

	// Compute the mask
	dw_set_mask = 8UL;

	// Get and save the previous value in the register
	INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, &dw_previous);

	// Compute the new value to be written
	dw_previous = dw_previous  | dw_set_mask;

	// Write it
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, dw_previous );

	return 0;
}

/*
 * Enables to enable or disable the secondary short circuit test
 * Must be done before testing the state of the secondary line
 * @retval
 * 	1: board handle given in parameter is wrong
 */
int i_APCI3701_PrimaryTransducerEnableDisableSecondaryShortCircuitTest ( struct pci_dev* pdev, BYTE b_flag )
{
	DWORD dw_previous = 0;
	DWORD dw_set_mask = 0;
	DWORD dw_reset_mask = 0;
	int i = 0;

	if ( ! pdev )
		return 1;

	// Compute the mask
	dw_set_mask = (DWORD) ( ((DWORD)b_flag) << 1 ) ;

	// Compute the reset mask
	dw_reset_mask = 0x2 & ( ~ (DWORD)(b_flag << 1) );

	// Get and save the previous value in the register
	INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, &dw_previous);

	// Compute the new value to be written
	dw_previous = ( dw_previous & ( 0xFFFFFFFFUL - dw_reset_mask )) | dw_set_mask;

	// Write it
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, dw_previous );

	// Change the board status
	APCI3701_PRIVDATA(pdev)->b_short_circuit_secondary_enable = b_flag;

	// No we have to wait until the bit is really taken in account by the board
	// THE FOLLOWING ALGO HAS TO BE CHANGED
	for ( i = 0; i < APCI3701_ITER_TIMEOUT; i++ )
	{
		INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, &dw_previous);
	}

	return 0;
}

/*
 * Enables to enable or disable the secondary open circuit test
 * Must be done before testing the state of the secondary line
 * @retval
 * 	1: board handle given in parameter is wrong
 */
int i_APCI3701_PrimaryTransducerEnableDisableSecondaryOpenCircuitTest ( struct pci_dev* pdev, BYTE b_flag )
{
	DWORD dw_previous = 0;
	DWORD dw_set_mask = 0;
	DWORD dw_reset_mask = 0;
	int i = 0;

	if ( ! pdev )
		return 1;

	// Compute the mask
	dw_set_mask = (DWORD) ( ((DWORD)b_flag) ) ;

	// Compute the reset mask
	dw_reset_mask = 0x1 & ( ~ (DWORD)(b_flag) );

	// Get and save the previous value in the register
	INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, &dw_previous );

	// Compute the new value to be written
	dw_previous = ( dw_previous & ( 0xFFFFFFFFUL - dw_reset_mask )) | dw_set_mask;

	// Write it
	OUTPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, dw_previous );

	// Change the board status
	APCI3701_PRIVDATA(pdev)->b_open_circuit_secondary_enable = b_flag;


	// No we have to wait until the bit is really taken in account by the board
	// THE FOLLOWING ALGO HAS TO BE CHANGED
	for ( i = 0; i < APCI3701_ITER_TIMEOUT; i++ )
	{
		INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_COMMAND, &dw_previous );
	}

	return 0;
}

/*
 * This function enables to test the primary line of the card
 * Before calling this function, the user must activate the primary line open circuit detection
 *
 * @retval
 * 	1: board handle given in parameter is wrong
 * 	2: the primary line open circuit detection is not enabled
 */
int i_APCI3701_test_primary_line ( struct pci_dev* pdev, uint32_t* status)
{
	if ( ! pdev)
		return 1;

	if ( APCI3701_PRIVDATA(pdev)->b_open_circuit_primary_enable == 0 )
		return 2;

	// We are now sure that the open circuit on primary line is enabled

	// Read the status
	// 0 if nothing detected
	// 1 if open circuit detected
	// 2 if short circuit detected
	// 3 if short circuit and open circuit detected
	INPDW_MEM( GET_MEM_BAR3(pdev), APCI3701_DIAGNOSTIC_STATUS, status );

	return 0;
}
