/** @file vtable.h
*
* @author Sylvain Nahas
*
* A vtable is an area of pointers to ioctl-implementing functions
*/

/** @par LICENCE
* @verbatim
 Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code and the documentation.
        
        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 shoud find the complete GPL in the COPYING file accompanying 
    this source code. 
* @endverbatim
*/

#ifndef __APCI3600_VTABLE_H__
#define __APCI3600_VTABLE_H__

/** A vtable is an area of pointer to functions implementing the ioctl calls.
 * The cmd are indexes from 1, the address from 0. 
 * Here we lose the field index 0 [sizeof(void*) of memory], 
 * but it avoid to decrement value during each call.
 * 
 * Type definition : allows latter use in board's private data, if needed
 * 
 * @note __APCI3600_UPPER_IOCTL_CMD must be defined in apci3600.h
 * 
 * */
//typedef __do_fcn *vtable_t[__APCI3600_UPPER_IOCTL_CMD + 1];

/** number of elements in the vtable.
 * 
 * allows to be independant of any macro used in vtable's definition.
 * evaluation is one at compile time.
 * */
#define VTABLE_ELEMENT_NB(__vtable)  ( sizeof(__vtable) / (sizeof(void*)) )


/* vtable for general board */
extern __do_fcn * apci3600_vtable_base[__APCI3600_BASE_UPPER_IOCTL_CMD + 1];

/* Analog Output 0 */
/* Analog Output 1 */
extern __do_fcn_with_id * apci3600_vtable_analog_output[__APCI3600_ANALOG_OUTPUT_UPPER_IOCTL_CMD + 1];

/* Analog Input Module 0 */
/* Analog Input Module 1 */
/* Analog Input Module 2 */
/* Analog Input Module 3 */
extern __do_fcn_with_id * apci3600_vtable_analog_input[__APCI3600_ANALOG_INPUT_UPPER_IOCTL_CMD + 1];
/* Chronometer 0 */
/* Chronometer 1 */
/* Chronometer 2 */
/* Chronometer 3 */
extern __do_fcn_with_id * apci3600_vtable_chrono[__APCI3600_CHRONOMETER_UPPER_IOCTL_CMD + 1];

/* digital input */
extern __do_fcn * apci3600_vtable_digital_input[__APCI3600_DIGITAL_INPUT_UPPER_IOCTL_CMD + 1];

/* digital output */
extern __do_fcn * apci3600_vtable_digital_output[__APCI3600_DIGITAL_OUTPUT_UPPER_IOCTL_CMD + 1];

/* external trigger */
extern __do_fcn * apci3600_vtable_external_trigger[__APCI3600_EXTERNAL_TRIGGER_UPPER_IOCTL_CMD + 1];

/* call all the above */
void apci3600_init_vtables(void);

/** Affect an vtable entry.
 * 
 *  @return 0 if OK, -1 if problem */
//extern int __APCI_3600_DECLARE_IOCTL_HANDLER (vtable_t vtable, unsigned int cmd__, __do_fcn * handler__ptr);

//------------------------------------------------------------------------------
/** Affect an vtable entry.
 * 
 * @return 0 if OK, -1 if problem 
 */
#define __APCI_3600_DECLARE_IOCTL_HANDLER(__vtable ,__cmd,  __handler_ptr) { if ( _IOC_NR(__cmd) > (VTABLE_ELEMENT_NB(__vtable)-1)) { printk(KERN_WARNING "%s: ioctl %lu: vtable entry index is over table boundaries (%lu elements)\n",__FUNCTION__,_IOC_NR(__cmd),VTABLE_ELEMENT_NB(__vtable) ); } else  { __vtable[_IOC_NR(__cmd)] = __handler_ptr; } ; }

//------------------------------------------------------------------------------
/** This function initialise a vtable (set all entry to dummy)
 * 
 * @param vtable VTABLE to intialise
 * 
 * */
#define apci3600_dummyze_vtable(__vtable, __dummyfcn ) \
{ \
	int i;\
	for ( i=0; i< VTABLE_ELEMENT_NB(__vtable) ; i++ )\
	{\
		__vtable[i] = __dummyfcn;\
	}\
}

#endif // __VTABLE_H__
