#ifndef __APCI2016_PRIVATE__
#define __APCI2016_PRIVATE__

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

/** @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
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/pci.h> // struct pci_dev
#include <linux/list.h>
#include <linux/fs.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)
#include <asm/uaccess.h>
#else
    #include <linux/uaccess.h>
#endif
#include <asm/io.h>
#include <linux/init.h>
#include "apci2016.h"


#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
#define __user 
#endif

/** @file apci2016-private.h
*
* stores definitions private to the driver
*/

/** private data 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 apci2016_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 apci2016_count;
extern unsigned int apci2016_majornumber;

#define __DRIVER_NAME "apci2016"

/* /dev function */
/* Asynchronous IO signal implementation - send a SIGIO to all registered processes*/
/* If using signal to inform user mode, uncomment following line: */
// int apci1648_fasync_lookup(int fd, struct file *filp, int mode);
int apci2016_open_lookup (struct inode *inode, struct file *filp);
int apci2016_release_lookup (struct inode *inode,struct file *filp);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
        int apci2016_ioctl_lookup (struct inode *inode,
                                                           struct file *filp,
                                                           unsigned int cmd,
                                                           unsigned long arg);
#else
        long apci2016_ioctl_lookup (struct file *filp,
                                                                unsigned int cmd,
                                                                unsigned long arg);
#endif
/* actual FS functions  */
int apci2016_do_ioctl(struct pci_dev * dev, unsigned int cmd, unsigned long arg);

/* FS functions  */
void apci2016_proc_init(void);
void apci2016_proc_release(void);
void apci2016_proc_create_device(struct pci_dev * dev, unsigned int minor_number);
void apci2016_proc_release_device(struct pci_dev * dev);
int apci2016_fasync(int fd, struct file *filp, int mode);


/* internal driver data */
struct apci2016_str_BoardInformations
{
   int OutputMemoryStatus; /**< Digital Output Memory Status (0: not active, 1: active) */     
   uint16_t DigitalOutputState; /**< Memory field for digital output state */
   int WatchdogIsConfigured; /**< caches watchdog configuration state (0: unconfigured, 1: configured ) */
   spinlock_t lock; /**< protect the board data */
};

static __inline__ void apci2016_init_priv_data(struct apci2016_str_BoardInformations * data)
{
	data->OutputMemoryStatus = 0; 
	data->DigitalOutputState = 0; 
	data->WatchdogIsConfigured = 0;
	spin_lock_init(& (data->lock) );	
}

static __inline__ struct apci2016_str_BoardInformations * APCI2016_PRIVDATA(struct pci_dev * pdev)
{
	return (struct apci2016_str_BoardInformations *) pci_get_drvdata(pdev);
}

/* return 1 if memory on, else 0 */
static __inline__ int APCI2016_OUTP_MEM_ON(struct pci_dev * pdev)
{
	return  (APCI2016_PRIVDATA(pdev)->OutputMemoryStatus);
}

static __inline__ void APCI2016_LOCK(struct pci_dev * pdev, unsigned long * flags)
{
	spin_lock_irqsave(& (APCI2016_PRIVDATA(pdev)->lock) , *flags );
}

static __inline__ void APCI2016_UNLOCK(struct pci_dev * pdev, unsigned long flags)
{
	spin_unlock_irqrestore(& (APCI2016_PRIVDATA(pdev)->lock) , flags );
	//printk(KERN_INFO "spin_unlock\n");	
}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)
#undef __user 
#endif

#include "api.h"
#include "iomap.h"

#endif //__APCI2016_PRIVATE__
