 /* @file privadata.h
  * 
  * @brief Holds definition for driver's private data and its manipulation functions. 
  * 
  * 
  * 
  */

/** @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 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 __APCIE1532_PRIVDATA_H_
#define __APCIE1532_PRIVDATA_H_

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)		
	#include <asm/semaphore.h>
#else
	#include <linux/semaphore.h>
#endif

#include <apcie1532-events.h>
#include <apcie1532-kapi.h>
#include "fifo.h"

#define APCIE1532_SIZE_EVENT_FIFO 20

DECLARE_NEW_FIFO_TYPE(apcie1532_event_fifo_t,APCIE1532_SIZE_EVENT_FIFO,apcie1532_event_t);

/* internal driver data */
struct apcie1532_str_BoardInformations
{
	struct semaphore sem; /**< semaphore protect the board data */

	uint32_t OutputMemoryStatus;    /**< Digital Output Memory Status (0: not active, 1: active) */     
	uint32_t RegisterDigitalOutput;	/**< Map the digital output register */	
	/* field used to implement linked list */
	struct pci_dev * previous; /**< previous in known-devices linked list */
	struct pci_dev * next; /**< next in known-devices linked list */
	
	apcie1532_event_fifo_t evtfifo; /* FIFO of events */
	wait_queue_head_t evt_wq; 		/* wait queue */
	APCIE1532_user_interrupt_t * user_interrupt_handler;
	
};

/** initialise board's private data - fill it when adding new members and ioctl handlers */
static __inline__ void apcie1532_init_priv_data(struct apcie1532_str_BoardInformations * data)
{
	/* Initialize the board structure */
	memset (data, 0, sizeof (struct apcie1532_str_BoardInformations));
	
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
	init_MUTEX( &(data->sem) );	
#else
	sema_init( &(data->sem), 1 );
#endif
	
	apcie1532_event_fifo_t_initialise( &(data->evtfifo) );
	init_waitqueue_head( &(data->evt_wq) );
	data->user_interrupt_handler = NULL;	
}

/** typed cast (safer to use) */
static __inline__ struct apcie1532_str_BoardInformations * APCIE1532_PRIVDATA(struct pci_dev * pdev)
{	
	return (struct apcie1532_str_BoardInformations *) pci_get_drvdata(pdev);	
}

/** used to lock the board - 
 * may be interrupted : check return value 
 * like that:
 * if (APCIE1532_DOWN(pdev))
 * 	return -ERESTARTSYS;
 * 
 * */
static inline int APCIE1532_LOCK(struct pci_dev * pdev, unsigned long * flags)
{
	return down_interruptible(&(APCIE1532_PRIVDATA(pdev)->sem));
}

/** release the semaphore */
static inline void APCIE1532_UNLOCK(struct pci_dev * pdev, unsigned long flags)
{
	up(&(APCIE1532_PRIVDATA(pdev)->sem));
}

/* EVENTS */

static inline int apcie1532_evt_add(struct pci_dev * pdev, apcie1532_event_t * evt, int count)
{
	return apcie1532_event_fifo_t_add( &(APCIE1532_PRIVDATA(pdev)->evtfifo), evt, count );
}

static inline int apcie1532_evt_retrieve(struct pci_dev * pdev, apcie1532_event_t * evt, int count)
{
	return apcie1532_event_fifo_t_retrieve( &(APCIE1532_PRIVDATA(pdev)->evtfifo), evt, count );
}

static inline int apcie1532_evt_count(struct pci_dev * pdev)
{
	return apcie1532_event_fifo_t_count( &(APCIE1532_PRIVDATA(pdev)->evtfifo));
}

/* wakeup all (interruptible sleeping) processes waiting for event on this board */
static inline int apcie1532_evt_wakeup(struct pci_dev * pdev)
{
	wake_up_interruptible( &(APCIE1532_PRIVDATA(pdev)->evt_wq) );
	return 0;
}

/* this function is for processes that want to sleep waiting an for event in the FIFO */
static inline int apcie1532_evt_wait(struct pci_dev * pdev)
{
	register struct apcie1532_str_BoardInformations * drvdata = APCIE1532_PRIVDATA(pdev);
	/* sleep until process interrupted or evtfifo.count is superior to zero */
	if ( wait_event_interruptible( drvdata->evt_wq, (drvdata->evtfifo.count > 0) ) ) 
	{
		/* process has been interrupted */
    	return -ERESTARTSYS;
    }
    return 0;
}

#endif // __APCIE1532_PRIVDATA_H_
