#ifndef __APCI1516_PRIVATE__
#define __APCI1516_PRIVATE__

/** @file apci1516-private.h
*
* @author Sylvain Nahas
*
* This header contains private definitions (not to be seen by external code)
*/

/** @par LICENCE
* @verbatim
   Copyright (C) 2009  ADDI-DATA GmbH for the source code of this module.
        
   ADDI-DATA GmbH
   Airpark Business Center
   Airport Boulevard B210
   77836 Rheinm�nster
   Germany
   Tel: +49(0)7229/1847-0
   Fax: +49(0)7229/1847-200
   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
*/

#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
	#include <linux/config.h>
#else
	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
		#include <linux/autoconf.h>
	#else
		#include <generated/autoconf.h>
	#endif
#endif

#include <linux/spinlock.h>
#include <linux/ioctl.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pci.h> // struct pci_dev
#include <asm/io.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)
	#include <asm/system.h>
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)
    #include <asm/uaccess.h>
#else
    #include <linux/uaccess.h>
#endif
#include <asm/bitops.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/proc_fs.h>

#include <apci.h>
#include <apci1516.h>

/** ressources of a board */

static __inline__ unsigned long GET_BAR0(struct pci_dev * pdev)
{
	return pdev->resource[0].start;
}

static __inline__ unsigned long GET_BAR1(struct pci_dev * pdev)
{
	return pdev->resource[1].start;
}

static __inline__ unsigned long GET_BAR2(struct pci_dev * pdev)
{
	return pdev->resource[2].start;
}

static __inline__ unsigned long GET_BAR3(struct pci_dev * pdev)
{
	return pdev->resource[3].start;
}

/** Utility fonction that returns 0 if the given index corresponds to a card already configured.
 *
 * @param count Number of board
 * @param index Minor number to check
 *
 * @return 0 if minor number valid, not 0 otherwise
 *
 * count ranges from 1 to ...
 * index ranges from 0 to ...
 *
 * */

static __inline__ int apci1516_INDEX_NOT_VALID(atomic_t * count , unsigned int index )
{
	volatile unsigned int __count =  atomic_read(count);
	if (index >= __count) return 1;
	return 0;

}


/* number of board detected by the kernel */
extern atomic_t apci1516_count;

#define __DRIVER_NAME "apci1516"

/* major number (attributed by the OS) */
extern unsigned int apci1516_majornumber;



/* dev function */
int apci1516_open_lookup (struct inode *inode, struct file *filp);
int apci1516_release_lookup (struct inode *inode,struct file *filp);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
        int apci1516_ioctl_lookup (struct inode *inode,
								   struct file *filp,
								   unsigned int cmd,
								   unsigned long arg);
#else
        long apci1516_ioctl_lookup (struct file *filp,
									unsigned int cmd,
									unsigned long arg);
#endif

/* kernel-side accessible API */
//int apci1516_do_ioctl(struct pci_dev * pdev, unsigned int cmd, unsigned long arg);

/*/proc functions  */
void apci1516_proc_init(void);
void apci1516_proc_release(void);
void apci1516_proc_create_device(struct pci_dev * dev, unsigned int minor_number);
void apci1516_proc_release_device(struct pci_dev * dev);

/* interrupt related function */
int apci1516_register_interrupt(struct pci_dev * pdev);
int apci1516_deregister_interrupt(struct pci_dev * pdev);


#include "api.h"
#include "privdata.h"

/** Import data from external scope into current scope.

@param _context Specify context 0: kernel context ; <> 0 : user context
@param _to : Destination address, in kernel space.
@param _from : Destination address, in user space or kernel space depending of context flag.
@param _count : Number of bytes to copy.

@return O if success, != 0 if failure


copy_from_user --  Copy a block of data from user space.
copy_from_user ( void * to, const void * from, size_t n);
to : Destination address, in kernel space.
from : Source address, in user space.
n : Number of bytes to copy.

When external scope is kernel code, this function uses memcpy.
When external scope is user code, this function uses copy_from_user.

Copy data from user space to kernel space.
Returns number of bytes that could not be copied. On success, this will be zero.
If some data could not be copied, this function will pad the copied data to the requested size using zero bytes.
User context only. This function may sleep.


memcpy --  Copy one area of memory to another
void * memcpy (void * dest, const void * src, size_t count);
dest : Where to copy to
src : Where to copy from
count :The size of the area.
The memcpy() function returns a pointer to dest.
This pointer cannot be NULL.
You should not use this function to access IO space, use memcpy_toio or memcpy_fromio instead.

*/

#define RETRIEVE_DATA(_apci_context,_apci_to,_apci_from,_apci_count) ( ( ( (_apci_context) == 0) )  ? ( ! ( memcpy( (_apci_to) , (_apci_from) , (_apci_count) ) ) ) : ( copy_from_user( (_apci_to) , (_apci_from) , (_apci_count) ) ) )

/*static __inline__ RETRIEVE_DATA(unsigned int _apci_context , void * _apci_to, void * _apci_from, size_t _apci_count)
{
	return  (  (_apci_context) == 0 )  ? ( ! ( memcpy( (_apci_to) , (_apci_from) , (_apci_count) ) ) ) :  copy_from_user( (_apci_to) , (_apci_from) , (_apci_count) ) ;
}*/

/** Export data from internal scope into external scope.

@param _context Specify context 0: kernel context ; <> 0 : user context
@param _to : Destination address, in kernel space.
@param _from : Destination address, in user space or kernel space depending of context flag.
@param _count : Number of bytes to copy.

@return O if success, != 0 if failure

When external scope is kernel code, this function uses memcpy.
When external scope is user code, this function uses copy_to_user.

copy_from_user --  Copy a block of data from user space.
copy_from_user ( void * to, const void * from, size_t n);
to : Destination address, in kernel space.
from : Source address, in user space.
n : Number of bytes to copy.

Copy data from user space to kernel space.
Returns number of bytes that could not be copied. On success, this will be zero.
If some data could not be copied, this function will pad the copied data to the requested size using zero bytes.
User context only. This function may sleep.


memcpy --  Copy one area of memory to another
void * memcpy (void * dest, const void * src, size_t count);
dest : Where to copy to
src : Where to copy from
count :The size of the area.
The memcpy() function returns a pointer to dest.
This pointer cannot be NULL.
You should not use this function to access IO space, use memcpy_toio or memcpy_fromio instead.

*/

#define EXPORT_DATA(_apci_context, _apci_to, _apci_from, _apci_count) ( ( ( (_apci_context) == 0) )  ? ( ! ( memcpy( (_apci_to) , (_apci_from) , (_apci_count) ) ) ) : ( copy_to_user( (_apci_to) , (_apci_from) , (_apci_count) ) ) )

#endif //__APCI1516_PRIVATE__
