/** @file board_information_kapi.c
 
   Access functions to read header on the eeprom.
 
   @par CREATION  
   @author Krauth Julien
   @date   11.08.06
   
   @par VERSION
   @verbatim
   $LastChangedRevision: 128 $
   $LastChangedDate: 2005-11-18 14:51:33 +0100 (Fri, 18 Nov 2005) $
   @endverbatim   
   
   @par COMPILER
   @verbatim
   Compiler	: gcc
   Version	:   
   kernel	: 
   @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 "xpci3xxx-private.h"

// If we have the right arch to use precompiled eeprom source files
#if defined(__x86_64__)
	#ifdef USE_ADDIEEPROM
		/**@def EXPORT_NO_SYMBOLS
		 * Function in this file are not exported.
		 */
		EXPORT_NO_SYMBOLS;
		// Use AMCC
		#define ADDI_EEPROM_READ	addi_eeprom_s5933_read
		#define GET_BAR			GET_BAR0
	#else
		// Export symbol to be used on ksamples
		EXPORT_SYMBOL(i_xpci3xxx_ReadEepromHeader_SerialNumber);
		EXPORT_SYMBOL(i_xpci3xxx_GetFirmwareVersion);
		EXPORT_SYMBOL(i_xpci3xxx_ReadEepromHeader_NbrOfOutputs);
		// Use EEPROM 93c76
		#define ADDI_EEPROM_READ	addi_eeprom_93c76_read_block
		#define GET_BAR			GET_BAR2
	#endif
#else
	// USE_ADDIEEPROM undefined
	/**@def EXPORT_NO_SYMBOLS
	 * Function in this file are not exported.
	 */
	EXPORT_NO_SYMBOLS;
#endif

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

#if defined(__x86_64__)

/** Get the xpci-3xxx serial number from the eeprom.
 *
 * @WARNING:	APCI3501 only
 *		To get the serial number of the board you have to edit _makefile:
 * 		echo "//#define USE_ADDIEEPROM	1" >> xpci3xxx-options.h; \ and remove // in the previous line.
 * 		This add functions to read the board header.
 * 		Once USE_ADDIEEPROM is defined you have to load	AddiEEPROM module before the xpci3xxx module.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 *
 * @retval	0	No error.
 * @retval	-1	Timeout.
 */
int i_xpci3xxx_ReadEepromHeader_SerialNumber (struct pci_dev *pdev, uint32_t *pdw_SerialNumber)
{
	uint16_t tw_SerialNumber[2] ={0};

	/* Get the board serial number */
	if ((ADDI_EEPROM_READ (2, GET_BAR(pdev), 0x102, tw_SerialNumber)) == -1) return (-1);

	*pdw_SerialNumber = tw_SerialNumber[0];
	*pdw_SerialNumber |= (tw_SerialNumber[1] << 16);

	XPCI3XXX_PRIVDATA(pdev)->dw_SerialNumber = *pdw_SerialNumber;

	return 0;
}

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

/** Get the xpci-3xxx FPGA firmware version from the eeprom.
 *
 * @param [in,out]      pdev    Pointer on the device structure.
 *
 * @retval      0       No error.
 * @retval      -1      Timeout.
 */
int i_xpci3xxx_GetFirmwareVersion (struct pci_dev *pdev, uint32_t *pdw_FirmwareVersion)
{
	INPDW(GET_BAR(pdev), pdw_FirmwareVersion);

	*pdw_FirmwareVersion = *pdw_FirmwareVersion >> 4;
	{
		char car1 = (char) (*pdw_FirmwareVersion >> 21) & 0x7F;
                char car2 = (char) (*pdw_FirmwareVersion >> 14) & 0x7F;
                char car3 = (char) (*pdw_FirmwareVersion >> 7) & 0x7F;
                char car4 = (char) (*pdw_FirmwareVersion) & 0x7F;

		if ( car1 < '0' || (car1 > '9' && car1 < 'A') || car1 > 'Z' )
		{
			return -2;
		}
		if ( car1 < '0' || (car1 > '9' && car1 < 'A') || car1 > 'Z' )
		{
			return -2;
		}
		if ( car1 < '0' || (car1 > '9' && car1 < 'A') || car1 > 'Z' )
		{
			return -2;
		}
		if ( car1 < '0' || (car1 > '9' && car1 < 'A') || car1 > 'Z' )
		{
			return -2;
		}
		*pdw_FirmwareVersion = (car1 << 24) + (car2 << 16) + (car3 << 8) + car4;

		XPCI3XXX_PRIVDATA(pdev)->dw_FirmwareVersion = *pdw_FirmwareVersion;
	}

	return 0;
}
//------------------------------------------------------------------------------

/** Get the xpci-3xxx output channels number from the eeprom.
 *
 * @param [in,out]	pdev	Pointer on the device structure.
 *
 * @retval	0	No error.
 * @retval	-1	Timeout.
 */
int i_xpci3xxx_ReadEepromHeader_NbrOfOutputs (struct pci_dev *pdev)
{
	uint16_t w_AnalogOutputMainHeaderAddress = 0;
	uint16_t w_AnalogOutputComponentAddress = 0;
	uint16_t w_NumberOfModuls = 0;
	uint16_t w_ModulCounter = 0;
	uint16_t w_FirstHeaderSize = 0;
	//uint16_t w_MainHeaderSize = 0;
	uint16_t w_NumberOfOutputs = 0;
	/* Get the Analog output header address */
	if ((ADDI_EEPROM_READ (1, GET_BAR(pdev), 0x11A, &w_AnalogOutputMainHeaderAddress)) == -1) return (-1);
	/* Compute the real analog output address */
	w_AnalogOutputMainHeaderAddress = w_AnalogOutputMainHeaderAddress + 0x100; //0x100: Offset of the Header EEPROM

	/* Get the number of moduls */
	if ((ADDI_EEPROM_READ (1, GET_BAR(pdev), w_AnalogOutputMainHeaderAddress + 0x06, &w_NumberOfModuls)) == -1) return (-1);


	w_NumberOfModuls &= 0x00FF;

	for (w_ModulCounter = 0; w_ModulCounter < w_NumberOfModuls; w_ModulCounter ++)
	{
        	/* Compute the component address */
		w_AnalogOutputComponentAddress = w_AnalogOutputMainHeaderAddress + (w_FirstHeaderSize * w_ModulCounter) + 8;

	        /* Read first header size */
     		if ((ADDI_EEPROM_READ (1, GET_BAR(pdev), w_AnalogOutputComponentAddress, &w_FirstHeaderSize)) == -1) return (-1);

	        w_FirstHeaderSize >>= 4;

        	/* Read number of outputs */
	     	if ((ADDI_EEPROM_READ (1, GET_BAR(pdev), w_AnalogOutputComponentAddress + 2, &w_NumberOfOutputs)) == -1) return (-1);

        	w_NumberOfOutputs >>= 4;

	        XPCI3XXX_PRIVDATA(pdev)->b_NumberOfAnalogOutput = w_NumberOfOutputs;
        }

        return (0);
}

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

#endif