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


#define APCIE1564_SIZE_EVENT_FIFO 20

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


DECLARE_NEW_FIFO_TYPE(apcie1564_event_fifo_t,APCIE1564_SIZE_EVENT_FIFO,apcie1564_event_t);

/* internal driver data */
struct apcie1564_str_BoardInformations
{
	uint32_t DigitalOutputRegister;   /* Digital Output Register */
	uint32_t  OutputMemoryState; /* Digital Output Memory State */
	/* 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 */

	spinlock_t lock; /**< protect the board data */
	apcie1564_event_fifo_t evtfifo; /* FIFO of events */
	wait_queue_head_t evt_wq; /* wait queue */
	APCIE1564_user_interrupt_t * user_interrupt_handler;
};

/** initialise board's private data - fill it when adding new members and ioctl handlers */
static __inline__ void apcie1564_init_priv_data(struct apcie1564_str_BoardInformations * data)
{
	memset(data,0,sizeof(struct apcie1564_str_BoardInformations));
	
	spin_lock_init(& (data->lock) );
	data->DigitalOutputRegister = 0;
	data->OutputMemoryState = 0;
	apcie1564_event_fifo_t_initialise( &(data->evtfifo) );
	init_waitqueue_head( &(data->evt_wq) );
	data->user_interrupt_handler = NULL;
}


static __inline__ struct apcie1564_str_BoardInformations * APCIE1564_PRIVDATA(struct pci_dev * pdev)
{
	return (struct apcie1564_str_BoardInformations *) pci_get_drvdata(pdev);
}

/* lock the board */
static __inline__ void APCIE1564_LOCK(struct pci_dev * pdev, unsigned long * flags)
{
	spin_lock_irqsave(& (APCIE1564_PRIVDATA(pdev)->lock), *flags );
}

/* unlock the board */
static __inline__ void APCIE1564_UNLOCK(struct pci_dev * pdev, unsigned long flags)
{
	spin_unlock_irqrestore(& (APCIE1564_PRIVDATA(pdev)->lock), flags );
}

/* EVENTS */

static inline int apcie1564_evt_add(struct pci_dev * pdev, apcie1564_event_t * evt, int count)
{
	return apcie1564_event_fifo_t_add( &(APCIE1564_PRIVDATA(pdev)->evtfifo), evt, count );
}

static inline int apcie1564_evt_retrieve(struct pci_dev * pdev, apcie1564_event_t * evt, int count)
{
	return apcie1564_event_fifo_t_retrieve( &(APCIE1564_PRIVDATA(pdev)->evtfifo), evt, count );
}

static inline int apcie1564_evt_count(struct pci_dev * pdev)
{
	return apcie1564_event_fifo_t_count( &(APCIE1564_PRIVDATA(pdev)->evtfifo));
}

/* wakeup all (interruptible sleeping) processes waiting for event on this board */
static inline int apcie1564_evt_wakeup(struct pci_dev * pdev)
{
	wake_up_interruptible( &(APCIE1564_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 apcie1564_evt_wait(struct pci_dev * pdev)
{
	register struct apcie1564_str_BoardInformations * drvdata = APCIE1564_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 // __APCIE1564_PRIVDATA_H__
