/** @file header-kapi.c
 
   Contains functions to get APCI-3701 header.
 
   @par CREATION  
   @author Krauth Julien
   @date   02.11.2006
   
   @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"

#include "eeprom/include/pcidetection.h"
#include "eeprom/include/typedef.h"
#include "eeprom/include/prototype.h"

EXPORT_SYMBOL(i_APCI3701_GetTransducerIndex);

/** Get board eeprom informations.
 * 
 * @retval 0:	No error.
 * @retval 1:	Wrong board handle.
 * @retval 2:	Fail to get the header size.
 * @retval 3:	Fail to get the eeprom size.
 * @retval 4:	Fail to allocate memory to store eeprom informations.
 * @retval 5:	Fail to get the eeprom informations.
 */
int i_APCI3701_GetBoardEeprom (struct pci_dev *pdev)
{
	str_AddressInformation s_Address;
	uint16_t w_HeaderSize = 0;
	uint16_t w_EepromSize = 0;
				
	if (!pdev) return 1;

	s_Address.b_AccessType = 1; /* IO access */
	s_Address.ui_Address = GET_BAR2(pdev);
	
	if (i_UpdateHeader_GetHeaderSize (&s_Address, &w_HeaderSize) != 0) {
		printk ("i_UpdateHeader_GetHeaderSize error\n");
		return 2;
	}	
	
	if (i_UpdateHeader_GetEepromSize (&s_Address, &w_EepromSize) != 0) {
		printk ("i_UpdateHeader_GetEepromSize error\n");
		return 3;
	}	

	/* Memory allocation for read the header */
	if ((APCI3701_PRIVDATA(pdev)->pw_BoardEeprom = kmalloc (w_EepromSize, GFP_KERNEL)) == NULL) {
		printk  ("Memory allocation error\n");                       
		return 4;
	}
	
	APCI3701_PRIVDATA(pdev)->pw_BoardHeader = &(APCI3701_PRIVDATA(pdev)->pw_BoardEeprom [256 / 2]);
          
	/* Read the board Eeprom */
	if (i_UpdateHeader_ReadBoardEeprom (&s_Address, 0, w_EepromSize, APCI3701_PRIVDATA(pdev)->pw_BoardEeprom) < 0) {
		printk  ("i_UpdateHeader_ReadBoardEeprom error\n"); 			
		kfree (APCI3701_PRIVDATA(pdev)->pw_BoardEeprom);
		return 5;
	}
	
	return 0;	
}

/** Get the transducer index for the specified transducer type.
 * 
 * @param [in] pdev             : The device to initialize.
 * @param [in] w_TransducerType	: Transducer type:<br>
 *										0:Schlumberger AGH 1<br>
 *										1:TESA GT21/GT22<br>
 *										2:TESA GT21HP/GT22HP<br>
 *										3:TESA GT61/GT62<br>
 *										4:ATI AXH/1.0<br>
 *										5:Mahr 1300<br>
 *										6:Mahr 1301/1303<br>
 *										7:Klingelnberg Sagamo<br>
 *										8:Solartron AX1.0S<br>
 *										9:Marposs F25<br>
 *										10:Peter Hirt T109/T110<br>
 *										11:Kn�bel +/-200 2m cable<br>
 *										12:RDP D5/200AG<br>
 *										13:Kn�bel +/-200 10m cable<br>
 *										14:Kn�bel +/-400 2m cable<br>
 *										15:Kn�bel +/-400 10m cable<br>
 *										16:Kn�bel +/-500 2m cable<br>
 *										17:Kn�bel +/-500 10m cable<br>
 *										18:Kn�bel +/-600 2m cable<br>
 *										19:Kn�bel +/-600 10m cable<br>
 *										20:Mahr P2004<br> 
 *										21:Solartron AX5.0SH<br>
 *										22:Solartron System 256 AX0.25S<br>
 *										23:Solartron System 256 AX0.5S<br>
 *										24:Solartron System 256 AX1.0S<br>
 *										25:Solartron System 256 AX2.5S<br>
 *										26:Solartron System 256 AX5.0S<br>
 *										27:Solartron System 256 AX10.0S<br>
 *										28:Schaevitz GCA121-250<br>
 *										29:Solartron AX1.0SH<br>
 *										30:RDP GTX 500Z-170 Ohm<br>
 *										31:RDP GTX 2500-110 Ohm<br>
 *										32:RDP GTX 2500P<br>
 *										33:RDP GTX 5000P<br>
 *										34:Solatron AX2.5H<br>
 *										35:Schaevitz PCA-116-100<br>
 *										36:Schaevitz PCA-116-300
 * @param [out] w_TransducerIndex	: This value has to be used with i_APCI3701_InitTransducerChannel.
 * 
 * @retval 0:	No error.
 * @retval 1:	Wrong board handle.
 * @retval 2:	Header informations not present.
 * @retval 3:	Transducer type not found.
 */
int   i_APCI3701_GetTransducerIndex (struct pci_dev *pdev, uint16_t w_TransducerType, uint16_t *w_TransducerIndex)
{
	str_LVDTSingleInformations* s_LVDTInformations = NULL;
	uint16_t w_NumberOfLVDTType = 0;
	int i = 0;
	int error = 0;

	if (!pdev) return 1;

	if (!APCI3701_PRIVDATA(pdev)->pw_BoardHeader) return 2;

	s_LVDTInformations = (str_LVDTSingleInformations*) kmalloc(APCI3701_MAX_LVDT_TRANSDUCERS * sizeof(str_LVDTSingleInformations), GFP_KERNEL);
	v_UpdateHeader_GetLVDT (APCI3701_PRIVDATA(pdev)->pw_BoardHeader, &w_NumberOfLVDTType, s_LVDTInformations);

	printk("Number of LVDT : %d \n", w_NumberOfLVDTType);

	*w_TransducerIndex = 0;
	error = 3; /* Transducer type not found */

	for (i=0; i<w_NumberOfLVDTType; i++)
	{
		printk("DEBUG, TYPE : %x \n", s_LVDTInformations[i].w_LVDTType);
		printk("DEBUG, w_LVDTSelectionTypeValue : %x \n", s_LVDTInformations[i].w_LVDTSelectionTypeValue);
		printk("DEBUG, open circuit secondary : %x \n", s_LVDTInformations[i].w_SecondaryOpenCircuitValue);
		printk("DEBUG, short circuit secondary : %x \n", s_LVDTInformations[i].w_SecondaryShortCircuitValue);


		if (s_LVDTInformations[i].w_LVDTType == w_TransducerType)
		{
			*w_TransducerIndex = s_LVDTInformations[i].w_LVDTSelectionTypeValue;
			error = 0;
			break;
		}
	}
	kfree(s_LVDTInformations);
	return error;
}

/*
 * Role: This function enables, given a transducer_type, to know the value for which we have an open or a short circuit for this transducer
 * These two values depend on the transducer type.
 *
 * @param [in]	pdev : a pointer to the structure of the device
 * @param [in]	transducer_type : the type of the transducer. For example, for a solartron AX1, the type is 0x18 or 24 in decimal. You can find these type thanks to the programm
 * set3701 (not available under Linux for the moment). It is the first column
 * @param [out]	short_circuit	: the short circuit value for the channel
 * @param [out]	short_circuit	: the open circuit value for the channel
 *
 *	Return value
 *	0	: no error
 *	1	: wrong board handler
 *	2	: board header not present
 */
int i_APCI3701_get_transducer_secondary_line_diagnostic_values ( struct pci_dev *pdev, uint16_t transducer_type, uint16_t* short_circuit, uint16_t* open_circuit)
{
	int i = 0;
	int ret = 3; // transducer type not found in the eeprom header

	str_LVDTSingleInformations* lvdt_info = NULL;
	uint16_t number_of_lvdt = 0;

	if ( ! pdev )
        {
		return 1;
        }

	if ( !APCI3701_PRIVDATA(pdev)->pw_BoardHeader )
        {
		return 2;
        }

	lvdt_info = (str_LVDTSingleInformations*) kmalloc(APCI3701_MAX_LVDT_TRANSDUCERS * sizeof(str_LVDTSingleInformations),GFP_KERNEL);

	// Fill in the array of LVDT
	v_UpdateHeader_GetLVDT (APCI3701_PRIVDATA(pdev)->pw_BoardHeader, &number_of_lvdt, lvdt_info);

	// Get the transducer information
	for ( i = 0 ; i < number_of_lvdt; i++ )
	{
		if ( lvdt_info[i].w_LVDTType == transducer_type )
		{
			*short_circuit = lvdt_info[i].w_SecondaryShortCircuitValue;
			*open_circuit = lvdt_info[i].w_SecondaryOpenCircuitValue;
			ret = 0;
			break;
		}
	}
	kfree(lvdt_info);

	return ret;
}

