 /* @file apcie1564-kapi.h
  * 
  * @brief Define the public kernel-land API for the APCI 1564 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 __APCIE1564_KAPI_H__
#define __APCIE1564_KAPI_H__

#include <linux/pci.h>
#include <apcie1564.h>
#include <apcie1564-events.h>

#ifndef __KERNEL__
	#error This header is for inclusion in kernel code only !
#endif

#ifdef __KERNEL__

/* DIGITAL INPUT ***********************************************************************/

/** Get the value of the digital input channels.
 * 
 * bit D0 returns the state of the digital input 0, D1 returns the state of the digital input 1, and so on...
 * 
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[out] input_value Pointer to a 32-bits variable that will hold the result.
 * 
 * @return 0 on success, non-zero on failure  
 * 
 * */
extern int APCIE1564_Read32DigitalInput(struct pci_dev *pdev, uint32_t* input_value);


/** Setup the digital input interrupt.
 * 
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] InterruptLogic : (0,1) - 0: OR, 1: AND
 * @param[in] InterruptMaskMode1 : only setting bit D4-D19 is legal ( each bit is an interruptible input ) - condition: InterruptMaskMode1 & (~0x000FFFF0) != 0 
 * @param[in] InterruptMaskMode2 : only setting bit D4-D19 is legal ( each bit is an interruptible input ) - condition: InterruptMaskMode2 & (~0x000FFFF0) != 0
 * 
 * @return 0 on success,  -EINVAL if parameters are incorrects
 */
 
extern int APCIE1564_InitAndStartDigitalInputInterrupt (struct pci_dev *pdev, int InterruptLogic, uint32_t InterruptMaskMode1,uint32_t InterruptMaskMode2);

/** Reset the digital input interrupt
 * 
 * previous parameter is cleared and interrupt deactivated 
 *  
 * @return 0 on success,  -EINVAL if parameters are incorrects
 */
extern int APCIE1564_ClearAndStopDigitalInputInterrupt (struct pci_dev *pdev);

/** Get the digital input interrupt configuration.
 * 
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] Enabled : (0,1) - 0: interruption is enabled, 1: interruption is disabled
 * @param[in] InterruptLogic : (0,1) - 0: OR, 1: AND
 * @param[in] InterruptMaskMode1 : (0,0x000FFFF0) 
 * @param[in] InterruptMaskMode2 : (0,0x000FFFF0)
 * 
 * @return 0 on success,  -EINVAL if parameters are incorrects
 */
 
extern int APCIE1564_GetDigitalInputInterruptConfig (struct pci_dev *pdev, int * Enabled, int * InterruptLogic, uint32_t * InterruptMaskMode1, uint32_t * InterruptMaskMode2);

/* DIGITAL OUTPUT ***********************************************************************/

/** Set the value of the specified digital output channels to 1.
 * 
 * bit D0 gives the value for the digital output 0, D1 gives the value for the digital output 1, and so on...
 * 
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] arg 32-bits variable that gives the channel(s) to modify.
 * 
 * @return 0 on success, non-zero on failure  
 * 
 */
extern int APCIE1564_Set32DigitalOutputOn(struct pci_dev *pdev, uint32_t arg);

/** Set the value of the specified digital output channels to 0.
 *
 * bit D0 gives the value for the digital output 0, D1 gives the value for the digital output 1, and so on...
 *
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] arg 32-bits variable that gives the channel(s) to modify.
 *
 * @return 0 on success, non-zero on failure
 *
 */
extern int APCIE1564_Set32DigitalOutputOff(struct pci_dev *pdev, uint32_t arg);

/** Set the Digital Output Memory Mode to ON
 *
 * @param[in] pdev Pointer to the PCI device to access.
 *
 * @return 0 on success, non-zero on failure
 *
 */
extern int APCIE1564_SetOutputMemoryOn(struct pci_dev *pdev);

/** Set the Digital Output Memory Mode to OFF 
 *
 * @param[in] pdev Pointer to the PCI device to access.
 *
 * @return 0 on success, non-zero on failure
 *
 */
extern int APCIE1564_SetOutputMemoryOff(struct pci_dev *pdev);

/** Get the value of the digital output channels.
 *
 * bit D0 returns the state of the digital output 0, D1 returns the state of the digital output 1, and so on...
 *
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[out] output_value Pointer to a 32-bits variable that will hold the result.
 *
 * @return 0 on success, non-zero on failure
 *
 */
extern int APCIE1564_Read32DigitalOutput(struct pci_dev *pdev, uint32_t* output_value);

/* COUNTER ***********************************************************************/
 
/** Initialise and start a counter. 
 * 
 * Interrupt is enabled.
 * 
 * @param[in] pdev Pointer to the PCI device to access. 
 * @param[in] CounterIndex  : Index of the counter to configure :(0,2) 
 * @param[in] Counter ReloadValue: (1,0xFFFFFFFF) 
 * @param[in] DirectionSelection: (0,1) 0: down count 1: up count
 * @param[in] LevelSelection: (1,2,3)  
 * 		1 : Counter count each low level \n
 *      2 : Counter count each high level \n
 *      3 : Counter count each high and low level \n 
 */
extern int APCIE1564_CounterInitAndStart(struct pci_dev *pdev, uint32_t CounterIndex, uint32_t ReloadValue, unsigned long DirectionSelection, unsigned long LevelSelection);

/** Get current counter value
 * 
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] CounterIndex Index of the counter (0,1,2)
 * @param[out] Value Current counter value
 * 
 * @return 0 on success, -EINVAL if a parameter is incorrect
 */ 
extern int APCIE1564_ReadCounterValue(struct pci_dev *pdev, uint32_t CounterIndex, uint32_t * Value);

/** Stop the counter.
 * 
 * Interrupt from this counter is disabled.
 * 
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] CounterIndex Index of the counter (0,1,2)
 * 
 * @return 0 on success, -EINVAL if a parameter is incorrect
 */
extern int APCIE1564_CounterStop(struct pci_dev *pdev, uint32_t CounterIndex);

/** Trigger the counter
 * 
 * if counter direction is 0 (down) the counter is reset to reload value
 * if counter direction is 1 (up) the counter is reset to 0
 *  
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] CounterIndex Index of the counter (0,1,2)
 * 
 * @return 0 on success, -EINVAL if a parameter is incorrect
 */
extern int APCIE1564_CounterTrigger(struct pci_dev *pdev, uint32_t CounterIndex);

/** Get current counter status.
 *  
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] CounterIndex Index of the counter (0,1,2)
 * @param[out] SoftwareTriggerStatus ( not relevant for counter ) 
 * @param[out] SoftwareClearStatus ( not relevant for counter )
 * @param[out] OverflowStatus 1 if the counter has overflowed 
 *  
 * @return 0 on success, -EINVAL if a parameter is incorrect
 */

extern int APCIE1564_CounterGetStatus(struct pci_dev *pdev, uint32_t CounterIndex, uint32_t * SoftwareTriggerStatus, uint32_t * SoftwareClearStatus, uint32_t * OverflowStatus);

/** Returns the config register of the given counter
 *  
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] CounterIndex Index of the counter (0,1,2)
 * @param[out] CounterConfig Configuration register 
 * 
 * @return 0 on success, -EINVAL if a parameter is incorrect
 */
extern int APCIE1564_CounterGetConfigRegister(struct pci_dev *pdev, uint32_t CounterIndex, uint32_t * CounterConfig);

/** Reset the counter configuration  
 *  
 * Stop the counter and clear the configuration
 * 
 * @param[in] pdev Pointer to the PCI device to access.
 * @param[in] CounterIndex Index of the counter (0,1,2) 
 * 
 * @return 0 on success, -EINVAL if a parameter is incorrect
 */

extern int APCIE1564_CounterReset(struct pci_dev *pdev, uint32_t CounterIndex);

typedef void APCIE1564_user_interrupt_t(struct pci_dev *pdev, apcie1564_event_t* evt);

/** Set the user interrupt callback  
 *
 * User interrupt callback is function of type APCIE1564_user_interrupt_t called when an event ( an interrupt )
 * happens. This function registers the user function in the board.
 *    
 * @param[in] pdev Pointer to the PCI device to access. 
 * 
 * @return 0 on success, -EINVAL if a parameter is incorrect, -EBUSY if an was interrupt already registered in the board 
 */
extern int APCIE1564_SetInterruptCallback(struct pci_dev *pdev, APCIE1564_user_interrupt_t user_interrupt  );

/** Clear the user interrupt callback reference in the driver.  
 *  
 * @param[in] pdev Pointer to the PCI device to access. 
 * 
 * @return 0 on success, -EINVAL if a parameter is incorrect
 */
extern int APCIE1564_ClearInterruptCallback(struct pci_dev *pdev);


/** find a apcie1564 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.
 */
struct pci_dev * apcie1564_lookup_board_by_index(unsigned int index);


//----------------------------------------------------------------------------
/** return a pointer to the lock protecting the board */
extern spinlock_t * APCIE1564_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 APCIE1564_lock(struct pci_dev *pdev, unsigned long * flags)
{
        spin_lock_irqsave(APCIE1564_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 APCIE1564_unlock(struct pci_dev *pdev, unsigned long flags)
{
        spin_unlock_irqrestore(APCIE1564_get_lock(pdev), flags);
}

#endif // __KERNEL__

#endif // __APCIE1564_KAPI_H__
