/** @file read.c
*
* @author Sylvain Nahas
*
* implements read() syscall
* 
*/

/** @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/fs.h>
#include "apci3701-private.h"

EXPORT_NO_SYMBOLS;

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

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
	#define __iomem
#endif

static ssize_t apci3701_read_autorefresh(struct file *filep, char __user * buff, size_t count, loff_t * offp)
{
	register struct pci_dev * pdev = filep->private_data;
	uint32_t values[17]; /* hold read value */
	size_t buffsz = 0;
		
	/* below is a locking algorithm that put the calling to sleep if no data is available 
	 * note that the process must be wake'd up elsewhere using apci3701_data_wakeup(pdev) 
	 */
	if ( !APCI3701_ACQUISITION_STARTED(pdev) )
	{
		/* nothing to read */

		/* handle non blocking IO */		
		if ( filep->f_flags& O_NONBLOCK )
			return -EAGAIN;
		
		/* wait to be waked up */
		if ( wait_event_interruptible( APCI3701_PRIVDATA(pdev)->data_wq, APCI3701_ACQUISITION_STARTED(pdev) ) )
			return -ERESTARTSYS;
	}
	/* data are there */
	
	/* returned values are in this order: sequence counter, value for sequence 0 , ... 
	 * for autorefresh, maximum sequence size is 16 
	 * the maximum size is then 17*sizeof(uint32_t)
	 * 
	 * */
	{
		unsigned long irqstate;
		APCI3701_LOCK(pdev,&irqstate);
		{
			/* Read the sequence counter */
			INPDW_MEM(GET_MEM_BAR3(pdev), APCI3701_REG_SEQUENCE_COUNTER, &(values[0]) );
			
			/* compute bufer size ( including sequence counter ) */
			buffsz = sizeof(uint32_t) * ( 1 + APCI3701_PRIVDATA(pdev)->w_SequenceSize );
			
			/* Read value for each channel in the sequence */
			{
				int i_SeqIndex;
				for (i_SeqIndex=0; i_SeqIndex < APCI3701_PRIVDATA(pdev)->w_SequenceSize; i_SeqIndex++)
				{
					INPDW_MEM(GET_MEM_BAR3(pdev), (APCI3701_REG_AUTOREFRESH_VALUES_BASE + (APCI3701_PRIVDATA(pdev)->w_ChannelSequence[i_SeqIndex]*4)), &(values[1+i_SeqIndex]));
				}
			}
		}
		APCI3701_UNLOCK(pdev,irqstate);
	}
	/* return data to user */
	count = min(count, buffsz);
	
	if (copy_to_user(buff, values, count) )
	{
		return -EFAULT;
	}
	
	return count;
}


ssize_t apci3701_read(struct file *filep, char __user * buff, size_t count, loff_t * offp)
{
	return apci3701_read_autorefresh(filep, buff, count, offp);
}

