 /* @file apci3001-kapi.h
  * 
  * @brief Define the public Kernel API for the apci3001 ADDI-DATA board. 
  * 
  *
  */

/** @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 library is free software; you can redistribute it and/or modify it under 
 the terms of the GNU Lesser General Public License as published by the 
 Free Software Foundation; either version 2.1 of the License, 
 or (at your option) any later version.
 
 This library 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 Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License 
 along with this library; if not, write to the Free Software Foundation, 
 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
 
 You also shoud find the complete LGPL in the LGPL.txt file accompanying 
 this source code.
 
 @endverbatim
**/

#ifndef __APCI3001_KAPI_H__
#define __APCI3001_KAPI_H__

#include "apci.h"

#ifdef __KERNEL__

#include <linux/pci.h>

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

/** Initialize the analog input value.
 * 
 * @param [in] 	pdev			: The device to initialize.
 * @param [in]	b_ChannelNumber	: The analog input channel.
 * @param [in]	b_Gain			: Gain factor of the analog input: <br>
 *									- APCI3001_1_GAIN : Gain =  1 <br>
 *									- APCI3001_2_GAIN : Gain =  2 <br>
 *									- APCI3001_5_GAIN : Gain =  5 <br>
 *									- APCI3001_10_GAIN: Gain = 10
 * @param [in]	b_Polarity		: Polarity of the analog input: <br>
 *									- APCI3001_UNIPOLAR:  0V - +10V <br>
 *									- APCI3001_BIPOLAR: -10V - +10V
 * @param [in]	ui_ConvertTiming: The convert timing of the analog input: <br>
 *									from 10us up to 32767us
 * 
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.         
 * @retval 2: Number of the analog input is wrong.                
 * @retval 3: The selected gain is wrong.                         
 * @retval 4: The selected input voltage range is wrong.          
 * @retval 5: The selected conversion time is wrong.              
 * @retval 6: A wrong parameter has been passed for <br>              
 *			  b_InterruptFlag or the user interrupt routine has <br>  
 *			  not been installed.
 */                                                                           
extern INT i_APCI3001_InitAnalogInput (struct pci_dev *pdev, 
								BYTE b_ChannelNumber,
                                BYTE b_Gain, 
                                BYTE b_Polarity,
								UINT ui_ConvertTiming,
								BYTE b_InterruptFlag);

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

/** Start the analog input conversion.
 * 
 * @param [in] 	pdev			: The device to initialize.
 * 
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
extern INT i_APCI3001_StartAnalogInput (struct pci_dev *pdev);		

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

/** Read the analog input conversion bit.
 * 
 * Test the endo of conversion.
 * 
 * @param [in] 	pdev			: The device to initialize.
 * 
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The EOC flag is not set.
 */
extern INT i_APCI3001_ReadAnalogInputBit (struct pci_dev *pdev);

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

/** Read the analog input value.
 * 
 * @param [in] 	pdev			: The device to initialize.
 * @param [out]	ui_ReadValue	: The analog input value.
 * 
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
extern INT i_APCI3001_ReadAnalogInputValue (struct pci_dev *pdev, UINT *ui_ReadValue);
		
//------------------------------------------------------------------------------

/** Read more analog input.
 *
 * @param [in] 	pdev				: The device to initialize.
 * @param [in]	b_SequenzArraySize		: Size of the sequence array (1 to 16 elements).
 * @param [in]	pb_ChannelArray			: Channels to read (array size = b_SequenzArraySize).
 * @param [in]	pb_GainArray			: Gain selection array.
 * @param [in]	pb_PolarityArray		: Selection of the input.
 * @param [in]	ui_ConvertTiming		: Selection of the conversion time from 10 to 32767 us.
 * @param [in]	b_InterruptFlag			: This parameter has to be 0 or PCI3001_DISABLE.<br> 
 * 																The interrupt is not implemeted!
 *
 * @param [out]	pui_AnalogInputValueArray	: Read values.
 * 
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The size of the sequence table is wrong.
 * @retval 3: Wrong parameter found in table "pb_ChannelArray".
 * @retval 4: Wrong parameter found in table "pb_GainArray".
 * @retval 5: Wrong parameter found in table "pb_PolarityArray".
 * @retval 6: The selected conversion time is wrong.
 * @retval 7: A wrong parameter has been passed for b_InterruptFlag.
 * @retval 8: Time out.
 * 
 */
extern INT   i_APCI3001_ReadMoreAnalogInputs     (struct pci_dev *pdev, 
					   	BYTE    b_SequenzArraySize,
					   	BYTE *  pb_ChannelArray,
					   	BYTE * pb_GainArray,
					   	BYTE *  pb_PolarityArray,
					   	UINT    ui_ConvertTiming,
					   	BYTE b_InterruptFlag,
					   	UINT * pui_AnalogInputValueArray);

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

/** Initialize read more analog input.
 *
 * @param [in] pdev                 : The device to initialize.
 * @param [in] b_SequenzArraySize   : Size of the sequence array (1 to 16 elements).
 * @param [in] pb_ChannelArray      : Channels to read (array size = b_SequenzArraySize).
 * @param [in] pb_GainArray         : Gain selection array.
 * @param [in] pb_PolarityArray     : Selection of the input.
 * @param [in] ui_ConvertTiming     : Selection of the conversion time from 10 to 32767 us.
 * @param [in] b_InterruptFlag      : This parameter has to be 0 or PCI3001_DISABLE.<br> 
 *                                    The interrupt is not implemeted!
 * 
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The size of the sequence table is wrong.
 * @retval 3: Wrong parameter found in table "pb_ChannelArray".
 * @retval 4: Wrong parameter found in table "pb_GainArray".
 * @retval 5: Wrong parameter found in table "pb_PolarityArray".
 * @retval 6: The selected conversion time is wrong.
 * @retval 7: A wrong parameter has been passed for b_InterruptFlag.
 * @retval 8: Time out.
 */
INT i_APCI3001_InitReadMoreAnalogInput (struct pci_dev *pdev, 
                                       BYTE b_SequenzArraySize,
                                       BYTE *  pb_ChannelArray,
                                       BYTE * pb_GainArray,
                                       BYTE *  pb_PolarityArray,
                                       UINT ui_ConvertTiming,
                                       BYTE b_InterruptFlag);

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

/** Start read more analog input.
 *
 * @param [in]    pdev                 : The device to initialize.
 * @param [in]    b_SequenzArraySize   : Size of the sequence array (1 to 16 elements).
 * 
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The size of the sequence table is wrong.
 */
INT i_APCI3001_StartReadMoreAnalogInput (struct pci_dev *pdev, BYTE b_SequenzArraySize);

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

/** Test end of conversion of read more analog input.
 *
 * @param [in]    pdev  : The device to initialize.
 * 
 * @retval 0: No error (Conversion is not running).
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: Conversion is running.
 */
INT i_APCI3001_TestEndOfReadMoreConversion (struct pci_dev *pdev);

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

/** Start read more analog input.
 *
 * @param [in]    pdev                 : The device to initialize.
 * @param [in]    b_SequenzArraySize   : Size of the sequence array (1 to 16 elements).
 * @param [out]   pui_Values           : Read values.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The size of the sequence table is wrong.
 */
INT i_APCI3001_ReadMoreValues (struct pci_dev *pdev, BYTE b_SequenzArraySize, UINT * pui_Values);

//------------------------------------------------------------------------------
/** find a apci3001 device of a given index in the system PCI device list.
 * @param index The index (minor number) to lookup
 * @return A pointer to the device or NULL
 *
 * This function is used to map a minor number to an actual device.
 */
static __inline__  struct pci_dev * apci3001_lookup_board_by_index(unsigned int index)
{
	struct pci_dev * dev = NULL;	
	int i = 0;
	
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)		
	while ( (dev = pci_find_device(APCI3001_BOARD_VENDOR_ID,APCI3001_BOARD_DEVICE_ID,dev)) )
#else
	while ( (dev = pci_get_device(APCI3001_BOARD_VENDOR_ID,APCI3001_BOARD_DEVICE_ID,dev)) )
#endif
	{
		if (i == index) return dev;
		i++;
	}      

	return NULL;

}
//----------------------------------------------------------------------------
/** return a pointer to the lock protecting the board */
extern spinlock_t * apci3001_get_lock(struct pci_dev *pdev);
//----------------------------------------------------------------------------
/** lock the board using spin_lock_irqsave(), disabling local software and hardware interrupts
 * @param[in] pdev The device to acquire.
 * @param[out] flags interuption flag used with unlock() 
 *
 * This function is to be used before calling any kAPI function; BUT not in user interrupt handler where the board is already acquired.
 *  
 * @warning lock aren't reentrant, that means that you can not nest call to lock() 
 *  
 */
static inline void apci3001_lock(struct pci_dev *pdev, unsigned long * flags)
{
        spin_lock_irqsave(apci3001_get_lock(pdev), *flags);
}

//----------------------------------------------------------------------------
/** unlock the board using spin_lock_irqrestore()
 * @param[in] pdev The device to acquire.
 * @param[out] flags interuption flag initialised by lock() 
 *
 * This function is to be used before calling any kAPI function; BUT not in user interrupt handler where the board is already acquired.
 * 
 *  
 *  
 */
static inline void apci3001_unlock(struct pci_dev *pdev, unsigned long flags)
{
        spin_unlock_irqrestore(apci3001_get_lock(pdev), flags);
}

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

/** Read 4 digital input.
 * 
 * @param [in] pdev                 : The device to manage.
 * @param [out] b_DigitalInputValue : Digital input value.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
int i_APCI3001_Read4DigitalInput (struct pci_dev *pdev, uint8_t *b_DigitalInputValue);

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

/** Set digital output memory on.
 *
 * When output memory is setting on. Output state is holding, and <br>
 * the new output(s) is(are) set or reset.
 *
 * @param [in] pdev                 : The device to manage.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
int i_APCI3001_SetOutputMemoryOn (struct pci_dev *pdev);

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

/** Set digital output memory off.
 *
 * @param [in] pdev                 : The device to manage.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 */
int i_APCI3001_SetOutputMemoryOff (struct pci_dev *pdev);

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

/** Set 4 digital output on.
 *
 * @param [in] pdev                 : The device to manage.
 * @param [in] b_DigitalOutputValue : Digital output value.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The digital output value is wrong.
 */
int i_APCI3001_Set4DigitalOutputOn (struct pci_dev *pdev, uint8_t b_DigitalOutputValue);

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

/** Set 4 digital output off.
 *
 * Can only be used when i_APCI3001_SetOutputMemoryOn has been called.
 *
 * @param [in] pdev                 : The device to manage.
 * @param [in] b_DigitalOutputValue : Digital output value.
 *
 * @retval 0: No error.
 * @retval 1: The handle parameter of the board is wrong.
 * @retval 2: The digital output value is wrong.
 * @retval 3: Output memory is not activated (please use i_APCI3001_SetOutputMemoryOn).
 */
int i_APCI3001_Set4DigitalOutputOff (struct pci_dev *pdev, uint8_t b_DigitalOutputValue);

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


#endif // __KERNEL__

#endif // __APCI3001_KAPI_H__
