2008-10-31 23:39:12 +00:00
/**
* @ file me6000_ao . c
*
* @ brief ME - 6000 analog output subdevice instance .
* @ note Copyright ( C ) 2007 Meilhaus Electronic GmbH ( support @ meilhaus . de )
* @ author Guenter Gebhardt
* @ author Krzysztof Gantzke ( k . gantzke @ meilhaus . de )
*/
/*
* Copyright ( C ) 2007 Meilhaus Electronic GmbH ( support @ meilhaus . de )
*
* This file 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 should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# ifndef __KERNEL__
# define __KERNEL__
# endif
/* Includes
*/
# include <linux/version.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <asm/io.h>
# include <asm/uaccess.h>
# include <linux/types.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/workqueue.h>
# include "medefines.h"
# include "meinternal.h"
# include "meerror.h"
# include "medebug.h"
# include "meids.h"
# include "me6000_reg.h"
# include "me6000_ao_reg.h"
# include "me6000_ao.h"
/* Defines
*/
static int me6000_ao_query_range_by_min_max ( me_subdevice_t * subdevice ,
int unit ,
int * min ,
int * max , int * maxdata , int * range ) ;
static int me6000_ao_query_number_ranges ( me_subdevice_t * subdevice ,
int unit , int * count ) ;
static int me6000_ao_query_range_info ( me_subdevice_t * subdevice ,
int range ,
int * unit ,
int * min , int * max , int * maxdata ) ;
static int me6000_ao_query_timer ( me_subdevice_t * subdevice ,
int timer ,
int * base_frequency ,
long long * min_ticks , long long * max_ticks ) ;
static int me6000_ao_query_number_channels ( me_subdevice_t * subdevice ,
int * number ) ;
static int me6000_ao_query_subdevice_type ( me_subdevice_t * subdevice ,
int * type , int * subtype ) ;
static int me6000_ao_query_subdevice_caps ( me_subdevice_t * subdevice ,
int * caps ) ;
static int me6000_ao_query_subdevice_caps_args ( struct me_subdevice * subdevice ,
int cap , int * args , int count ) ;
/** Remove subdevice. */
static void me6000_ao_destructor ( struct me_subdevice * subdevice ) ;
/** Reset subdevice. Stop all actions. Reset registry. Disable FIFO. Set output to 0V and status to 'none'. */
static int me6000_ao_io_reset_subdevice ( me_subdevice_t * subdevice ,
struct file * filep , int flags ) ;
/** Set output as single */
static int me6000_ao_io_single_config ( me_subdevice_t * subdevice ,
struct file * filep ,
int channel ,
int single_config ,
int ref ,
int trig_chan ,
int trig_type , int trig_edge , int flags ) ;
/** Pass to user actual value of output. */
static int me6000_ao_io_single_read ( me_subdevice_t * subdevice ,
struct file * filep ,
int channel ,
int * value , int time_out , int flags ) ;
/** Write to output requed value. */
static int me6000_ao_io_single_write ( me_subdevice_t * subdevice ,
struct file * filep ,
int channel ,
int value , int time_out , int flags ) ;
/** Set output as streamed device. */
static int me6000_ao_io_stream_config ( me_subdevice_t * subdevice ,
struct file * filep ,
meIOStreamConfig_t * config_list ,
int count ,
meIOStreamTrigger_t * trigger ,
int fifo_irq_threshold , int flags ) ;
/** Wait for / Check empty space in buffer. */
static int me6000_ao_io_stream_new_values ( me_subdevice_t * subdevice ,
struct file * filep ,
int time_out , int * count , int flags ) ;
/** Start streaming. */
static int me6000_ao_io_stream_start ( me_subdevice_t * subdevice ,
struct file * filep ,
int start_mode , int time_out , int flags ) ;
/** Check actual state. / Wait for end. */
static int me6000_ao_io_stream_status ( me_subdevice_t * subdevice ,
struct file * filep ,
int wait ,
int * status , int * values , int flags ) ;
/** Stop streaming. */
static int me6000_ao_io_stream_stop ( me_subdevice_t * subdevice ,
struct file * filep ,
int stop_mode , int flags ) ;
/** Write datas to buffor. */
static int me6000_ao_io_stream_write ( me_subdevice_t * subdevice ,
struct file * filep ,
int write_mode ,
int * values , int * count , int flags ) ;
/** Interrupt handler. Copy from buffer to FIFO. */
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
static irqreturn_t me6000_ao_isr ( int irq , void * dev_id ) ;
# else
static irqreturn_t me6000_ao_isr ( int irq , void * dev_id , struct pt_regs * regs ) ;
# endif
/** Copy data from circular buffer to fifo (fast) in wraparound mode. */
int inline ao_write_data_wraparound ( me6000_ao_subdevice_t * instance , int count ,
int start_pos ) ;
/** Copy data from circular buffer to fifo (fast).*/
int inline ao_write_data ( me6000_ao_subdevice_t * instance , int count ,
int start_pos ) ;
/** Copy data from circular buffer to fifo (slow).*/
int inline ao_write_data_pooling ( me6000_ao_subdevice_t * instance , int count ,
int start_pos ) ;
/** Copy data from user space to circular buffer. */
int inline ao_get_data_from_user ( me6000_ao_subdevice_t * instance , int count ,
int * user_values ) ;
/** Stop presentation. Preserve FIFOs. */
int inline ao_stop_immediately ( me6000_ao_subdevice_t * instance ) ;
/** Function for checking timeout in non-blocking mode. */
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
static void me6000_ao_work_control_task ( void * subdevice ) ;
# else
static void me6000_ao_work_control_task ( struct work_struct * work ) ;
# endif
/* Functions
*/
static int me6000_ao_io_reset_subdevice ( me_subdevice_t * subdevice ,
struct file * filep , int flags )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
uint32_t tmp ;
uint32_t ctrl ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
ME_SUBDEVICE_ENTER ;
instance - > status = ao_status_none ;
instance - > ao_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ao_control_task ) ;
instance - > timeout . delay = 0 ;
instance - > timeout . start_time = jiffies ;
//Stop state machine.
err = ao_stop_immediately ( instance ) ;
//Remove from synchronous start.
spin_lock ( instance - > preload_reg_lock ) ;
tmp = inl ( instance - > preload_reg ) ;
tmp & =
~ ( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < < instance - >
ao_idx ) ;
outl ( tmp , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > preload_reg - instance - > reg_base , tmp ) ;
* instance - > preload_flags & =
~ ( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < < instance - >
ao_idx ) ;
//Reset triggering flag
* instance - > triggering_flags & = ~ ( 0x1 < < instance - > ao_idx ) ;
spin_unlock ( instance - > preload_reg_lock ) ;
if ( instance - > fifo ) {
//Set single mode, dissable FIFO, dissable external trigger, block interrupt.
ctrl = ME6000_AO_MODE_SINGLE ;
//Block ISM.
ctrl | =
( ME6000_AO_CTRL_BIT_STOP |
ME6000_AO_CTRL_BIT_IMMEDIATE_STOP ) ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
//Set speed
outl ( ME6000_AO_MIN_CHAN_TICKS - 1 , instance - > timer_reg ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
}
instance - > hardware_stop_delay = HZ / 10 ; //100ms
//Set output to 0V
outl ( 0x8000 , instance - > single_reg ) ;
PDEBUG_REG ( " single_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > single_reg - instance - > reg_base , 0x8000 ) ;
instance - > circ_buf . head = 0 ;
instance - > circ_buf . tail = 0 ;
instance - > preloaded_count = 0 ;
instance - > data_count = 0 ;
instance - > single_value = 0x8000 ;
instance - > single_value_in_fifo = 0x8000 ;
//Set status to signal that device is unconfigured.
instance - > status = ao_status_none ;
//Signal reset if user is on wait.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_single_config ( me_subdevice_t * subdevice ,
struct file * filep ,
int channel ,
int single_config ,
int ref ,
int trig_chan ,
int trig_type , int trig_edge , int flags )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
uint32_t ctrl ;
uint32_t sync ;
unsigned long cpu_flags ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. ID=%d \n " , instance - > ao_idx ) ;
// Checking parameters
if ( flags ) {
PERROR
( " Invalid flag specified. Must be ME_IO_SINGLE_CONFIG_NO_FLAGS. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( instance - > fifo ) { //Stream hardware (with or without fifo)
if ( ( trig_edge = = ME_TRIG_TYPE_SW )
& & ( trig_edge ! = ME_TRIG_EDGE_NONE ) ) {
PERROR
( " Invalid trigger edge. Software trigger has not edge. \n " ) ;
return ME_ERRNO_INVALID_TRIG_EDGE ;
}
if ( trig_type = = ME_TRIG_TYPE_EXT_DIGITAL ) {
switch ( trig_edge ) {
case ME_TRIG_EDGE_ANY :
case ME_TRIG_EDGE_RISING :
case ME_TRIG_EDGE_FALLING :
break ;
default :
PERROR ( " Invalid trigger edge. \n " ) ;
return ME_ERRNO_INVALID_TRIG_EDGE ;
}
}
if ( ( trig_type ! = ME_TRIG_TYPE_SW )
& & ( trig_type ! = ME_TRIG_TYPE_EXT_DIGITAL ) ) {
PERROR
( " Invalid trigger type. Trigger must be software or digital. \n " ) ;
return ME_ERRNO_INVALID_TRIG_TYPE ;
}
} else { //Single
if ( trig_edge ! = ME_TRIG_EDGE_NONE ) {
PERROR
( " Invalid trigger edge. Single output trigger hasn't own edge. \n " ) ;
return ME_ERRNO_INVALID_TRIG_EDGE ;
}
if ( trig_type ! = ME_TRIG_TYPE_SW ) {
PERROR
( " Invalid trigger type. Trigger must be software. \n " ) ;
return ME_ERRNO_INVALID_TRIG_TYPE ;
}
}
if ( ( trig_chan ! = ME_TRIG_CHAN_DEFAULT )
& & ( trig_chan ! = ME_TRIG_CHAN_SYNCHRONOUS ) ) {
PERROR ( " Invalid trigger channel specified. \n " ) ;
return ME_ERRNO_INVALID_TRIG_CHAN ;
}
/*
if ( ( trig_type = = ME_TRIG_TYPE_EXT_DIGITAL ) & & ( trig_chan ! = ME_TRIG_CHAN_SYNCHRONOUS ) )
{
PERROR ( " Invalid trigger channel specified. Must be synchronous when digital is choose. \n " ) ;
return ME_ERRNO_INVALID_TRIG_CHAN ;
}
*/
if ( ref ! = ME_REF_AO_GROUND ) {
PERROR
( " Invalid reference. Analog outputs have to have got REF_AO_GROUND. \n " ) ;
return ME_ERRNO_INVALID_REF ;
}
if ( single_config ! = 0 ) {
PERROR
( " Invalid single config specified. Only one range for anlog outputs is available. \n " ) ;
return ME_ERRNO_INVALID_SINGLE_CONFIG ;
}
if ( channel ! = 0 ) {
PERROR
( " Invalid channel number specified. Analog output have only one channel. \n " ) ;
return ME_ERRNO_INVALID_CHANNEL ;
}
ME_SUBDEVICE_ENTER ;
//Subdevice running in stream mode!
if ( ( instance - > status > = ao_status_stream_run_wait )
& & ( instance - > status < ao_status_stream_end ) ) {
PERROR ( " Subdevice is busy. \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_SUBDEVICE_BUSY ;
}
/// @note For single all calls (config and write) are erasing previous state!
instance - > status = ao_status_none ;
// Correct single mirrors
instance - > single_value_in_fifo = instance - > single_value ;
//Stop device
err = ao_stop_immediately ( instance ) ;
if ( err ) {
PERROR_CRITICAL ( " FSM IS BUSY! \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_SUBDEVICE_BUSY ;
}
if ( instance - > fifo ) { // Set control register.
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
// Set stop bit. Stop streaming mode (If running.).
ctrl = inl ( instance - > ctrl_reg ) ;
//Reset all bits.
ctrl =
ME6000_AO_CTRL_BIT_IMMEDIATE_STOP | ME6000_AO_CTRL_BIT_STOP ;
if ( trig_type = = ME_TRIG_TYPE_EXT_DIGITAL ) {
PINFO ( " External digital trigger. \n " ) ;
if ( trig_edge = = ME_TRIG_EDGE_ANY ) {
// ctrl |= ME6000_AO_CTRL_BIT_EX_TRIG_EDGE | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH;
instance - > ctrl_trg =
ME6000_AO_CTRL_BIT_EX_TRIG_EDGE |
ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH ;
} else if ( trig_edge = = ME_TRIG_EDGE_FALLING ) {
// ctrl |= ME6000_AO_CTRL_BIT_EX_TRIG_EDGE;
instance - > ctrl_trg =
ME6000_AO_CTRL_BIT_EX_TRIG_EDGE ;
} else if ( trig_edge = = ME_TRIG_EDGE_RISING ) {
instance - > ctrl_trg = 0x0 ;
}
} else if ( trig_type = = ME_TRIG_TYPE_SW ) {
PDEBUG ( " SOFTWARE TRIGGER \n " ) ;
instance - > ctrl_trg = 0x0 ;
}
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
} else {
PDEBUG ( " SOFTWARE TRIGGER \n " ) ;
}
// Set preload/synchronization register.
spin_lock ( instance - > preload_reg_lock ) ;
if ( trig_type = = ME_TRIG_TYPE_SW ) {
* instance - > preload_flags & =
~ ( ME6000_AO_SYNC_EXT_TRIG < < instance - > ao_idx ) ;
} else //if (trig_type == ME_TRIG_TYPE_EXT_DIGITAL)
{
* instance - > preload_flags | =
ME6000_AO_SYNC_EXT_TRIG < < instance - > ao_idx ;
}
if ( trig_chan = = ME_TRIG_CHAN_DEFAULT ) {
* instance - > preload_flags & =
~ ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ;
} else //if (trig_chan == ME_TRIG_CHAN_SYNCHRONOUS)
{
* instance - > preload_flags | =
ME6000_AO_SYNC_HOLD < < instance - > ao_idx ;
}
//Reset hardware register
sync = inl ( instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg inl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > preload_reg - instance - > reg_base , sync ) ;
sync & = ~ ( ME6000_AO_SYNC_EXT_TRIG < < instance - > ao_idx ) ;
sync | = ME6000_AO_SYNC_HOLD < < instance - > ao_idx ;
//Output configured in default mode (safe one)
outl ( sync , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > preload_reg - instance - > reg_base , sync ) ;
spin_unlock ( instance - > preload_reg_lock ) ;
instance - > status = ao_status_single_configured ;
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_single_read ( me_subdevice_t * subdevice ,
struct file * filep ,
int channel ,
int * value , int time_out , int flags )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
unsigned long j ;
unsigned long delay = 0 ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( flags & ~ ME_IO_SINGLE_NONBLOCKING ) {
PERROR ( " Invalid flag specified. %d \n " , flags ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( ( instance - > status > = ao_status_stream_configured )
& & ( instance - > status < = ao_status_stream_end ) ) {
PERROR ( " Subdevice not configured to work in single mode! \n " ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
}
if ( channel ! = 0 ) {
PERROR ( " Invalid channel number specified. \n " ) ;
return ME_ERRNO_INVALID_CHANNEL ;
}
if ( time_out < 0 ) {
PERROR ( " Invalid timeout specified. \n " ) ;
return ME_ERRNO_INVALID_TIMEOUT ;
}
ME_SUBDEVICE_ENTER ;
if ( ( ! flags ) & & ( instance - > status = = ao_status_single_run_wait ) ) { //Blocking mode. Wait for trigger.
if ( time_out ) {
delay = ( time_out * HZ ) / 1000 ;
if ( delay = = 0 )
delay = 1 ;
}
j = jiffies ;
//Only runing process will interrupt this call. Events are signaled when status change. This procedure has own timeout.
wait_event_interruptible_timeout ( instance - > wait_queue ,
( instance - > status ! =
ao_status_single_run_wait ) ,
( delay ) ? delay : LONG_MAX ) ;
if ( instance - > status = = ao_status_none ) {
PDEBUG ( " Single canceled. \n " ) ;
err = ME_ERRNO_CANCELLED ;
}
if ( signal_pending ( current ) ) {
PERROR ( " Wait on start of state machine interrupted. \n " ) ;
instance - > status = ao_status_none ;
ao_stop_immediately ( instance ) ;
err = ME_ERRNO_SIGNAL ;
}
if ( ( delay ) & & ( ( jiffies - j ) > = delay ) ) {
PDEBUG ( " Timeout reached. \n " ) ;
err = ME_ERRNO_TIMEOUT ;
}
* value =
( ! err ) ? instance - > single_value_in_fifo : instance - >
single_value ;
} else { //Non-blocking mode
//Read value
* value = instance - > single_value ;
}
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_single_write ( me_subdevice_t * subdevice ,
struct file * filep ,
int channel ,
int value , int time_out , int flags )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
unsigned long cpu_flags ;
unsigned long j ;
unsigned long delay = 0 ;
uint32_t sync_mask ;
uint32_t mode ;
uint32_t tmp ;
/// Workaround for mix-mode - begin
uint32_t ctrl = 0x0 ;
uint32_t status ;
/// Workaround for mix-mode - end
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( flags &
~ ( ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS |
ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING ) ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( ( instance - > status = = ao_status_none )
| | ( instance - > status > ao_status_single_end ) ) {
PERROR ( " Subdevice not configured to work in single mode! \n " ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
}
if ( channel ! = 0 ) {
PERROR ( " Invalid channel number specified. \n " ) ;
return ME_ERRNO_INVALID_CHANNEL ;
}
if ( value & ~ ME6000_AO_MAX_DATA ) {
PERROR ( " Invalid value provided. \n " ) ;
return ME_ERRNO_VALUE_OUT_OF_RANGE ;
}
if ( time_out < 0 ) {
PERROR ( " Invalid timeout specified. \n " ) ;
return ME_ERRNO_INVALID_TIMEOUT ;
}
ME_SUBDEVICE_ENTER ;
/// @note For single all calls (config and write) are erasing previous state!
//Cancel control task
PDEBUG ( " Cancel control task. idx=%d \n " , instance - > ao_idx ) ;
instance - > ao_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ao_control_task ) ;
// Correct single mirrors
instance - > single_value_in_fifo = instance - > single_value ;
//Stop device
err = ao_stop_immediately ( instance ) ;
if ( err ) {
PERROR_CRITICAL ( " FSM IS BUSY! \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_SUBDEVICE_BUSY ;
}
if ( time_out ) {
delay = ( time_out * HZ ) / 1000 ;
if ( delay = = 0 )
delay = 1 ;
}
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
instance - > single_value_in_fifo = value ;
if ( instance - > fifo ) {
ctrl = inl ( instance - > ctrl_reg ) ;
}
if ( instance - > fifo & ME6000_AO_HAS_FIFO ) { /// Workaround for mix-mode - begin
//Set speed
outl ( ME6000_AO_MIN_CHAN_TICKS - 1 , instance - > timer_reg ) ;
PDEBUG_REG ( " timer_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > timer_reg - instance - > reg_base ,
( int ) ME6000_AO_MIN_CHAN_TICKS ) ;
instance - > hardware_stop_delay = HZ / 10 ; //100ms
status = inl ( instance - > status_reg ) ;
//Set the continous mode.
ctrl & = ~ ME6000_AO_CTRL_MODE_MASK ;
ctrl | = ME6000_AO_MODE_CONTINUOUS ;
//Prepare FIFO
if ( ! ( ctrl & ME6000_AO_CTRL_BIT_ENABLE_FIFO ) ) { //FIFO wasn't enabeled. Do it.
PINFO ( " Enableing FIFO. \n " ) ;
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_FIFO ;
} else { //Check if FIFO is empty
if ( status & ME6000_AO_STATUS_BIT_EF ) { //FIFO not empty
PINFO ( " Reseting FIFO. \n " ) ;
ctrl & =
~ ( ME6000_AO_CTRL_BIT_ENABLE_FIFO |
ME6000_AO_CTRL_BIT_ENABLE_IRQ ) ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg -
instance - > reg_base , ctrl ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_FIFO ;
} else { //FIFO empty, only interrupt needs to be disabled!
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
}
}
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
//Write output - 1 value to FIFO
if ( instance - > ao_idx & 0x1 ) {
outl ( value < < = 16 , instance - > fifo_reg ) ;
PDEBUG_REG ( " fifo_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > fifo_reg - instance - > reg_base ,
value < < = 16 ) ;
} else {
outl ( value , instance - > fifo_reg ) ;
PDEBUG_REG ( " fifo_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > fifo_reg - instance - > reg_base ,
value ) ;
}
/// Workaround for mix-mode - end
} else { //No FIFO - always in single mode
//Write value
PDEBUG ( " Write value \n " ) ;
outl ( value , instance - > single_reg ) ;
PDEBUG_REG ( " single_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > single_reg - instance - > reg_base , value ) ;
}
mode = * instance - > preload_flags > > instance - > ao_idx ;
mode & = ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) ;
PINFO ( " Triggering mode: 0x%08x \n " , mode ) ;
spin_lock ( instance - > preload_reg_lock ) ;
sync_mask = inl ( instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg inl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > preload_reg - instance - > reg_base , sync_mask ) ;
switch ( mode ) {
case 0 : //0x00000000: Individual software
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ;
if ( instance - > fifo & ME6000_AO_HAS_FIFO ) { // FIFO - Continous mode
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ;
if ( ( sync_mask & ( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < < instance - > ao_idx ) ) ! = 0x0 ) { //Now we can set correct mode.
sync_mask & =
~ ( ( ME6000_AO_SYNC_EXT_TRIG |
ME6000_AO_SYNC_HOLD ) < < instance - >
ao_idx ) ;
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG
( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
}
} else { // No FIFO - Single mode: In this case resetting 'ME6000_AO_SYNC_HOLD' will trigger output.
if ( ( sync_mask & ( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < < instance - > ao_idx ) ) ! = ME6000_AO_SYNC_HOLD ) { //Now we can set correct mode. This is exception. It is set to synchronous and triggered later.
sync_mask & =
~ ( ME6000_AO_SYNC_EXT_TRIG < < instance - >
ao_idx ) ;
sync_mask | =
ME6000_AO_SYNC_HOLD < < instance - > ao_idx ;
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG
( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
}
}
instance - > single_value = value ;
break ;
case ME6000_AO_SYNC_EXT_TRIG : //0x00010000: Individual hardware
PDEBUG ( " DIGITAL TRIGGER \n " ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ;
if ( instance - > fifo & ME6000_AO_HAS_FIFO ) { // FIFO - Continous mode
if ( ( sync_mask & ( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < < instance - > ao_idx ) ) ! = 0x0 ) { //Now we can set correct mode.
sync_mask & =
~ ( ( ME6000_AO_SYNC_EXT_TRIG |
ME6000_AO_SYNC_HOLD ) < < instance - >
ao_idx ) ;
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG
( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
}
} else { // No FIFO - Single mode
if ( ( sync_mask &
( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < <
instance - > ao_idx ) ) ! = ME6000_AO_SYNC_HOLD ) {
//Now we can set correct mode
sync_mask & =
~ ( ME6000_AO_SYNC_EXT_TRIG < < instance - >
ao_idx ) ;
sync_mask | =
ME6000_AO_SYNC_HOLD < < instance - > ao_idx ;
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG
( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
}
}
break ;
case ME6000_AO_SYNC_HOLD : //0x00000001: Synchronous software
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ;
if ( ( sync_mask &
( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < <
instance - > ao_idx ) ) ! =
( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) ) {
//Now we can set correct mode
sync_mask | =
ME6000_AO_SYNC_EXT_TRIG < < instance - > ao_idx ;
sync_mask | = ME6000_AO_SYNC_HOLD < < instance - > ao_idx ;
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
}
//Set triggering flag
* instance - > triggering_flags | = 0x1 < < instance - > ao_idx ;
break ;
case ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) : //0x00010001: Synchronous hardware
PDEBUG ( " DIGITAL TRIGGER \n " ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ;
if ( ( sync_mask &
( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < <
instance - > ao_idx ) ) ! =
( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) ) {
//Now we can set correct mode
sync_mask | =
( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < <
instance - > ao_idx ;
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
}
//Set triggering flag
* instance - > triggering_flags | = 0x1 < < instance - > ao_idx ;
break ;
}
// spin_unlock(instance->preload_reg_lock); // Moved down.
if ( instance - > fifo ) { //Activate ISM (remove 'stop' bits)
ctrl & =
~ ( ME6000_AO_CTRL_BIT_EX_TRIG_EDGE |
ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH ) ;
ctrl | = instance - > ctrl_trg ;
ctrl & =
~ ( ME6000_AO_CTRL_BIT_STOP |
ME6000_AO_CTRL_BIT_IMMEDIATE_STOP ) ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
}
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
/// @note When flag 'ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS' is set than output is triggered. ALWAYS!
2009-01-07 22:31:57 +00:00
PINFO ( " <%s> start mode= 0x%08x %s \n " , __func__ , mode ,
2008-10-31 23:39:12 +00:00
( flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS ) ? " SYNCHRONOUS " :
" " ) ;
if ( instance - > fifo & ME6000_AO_HAS_FIFO ) { // FIFO - Continous mode
if ( flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS ) { //Trigger outputs
//Add channel to start list
outl ( sync_mask |
( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ,
instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask | ( ME6000_AO_SYNC_HOLD < <
instance - > ao_idx ) ) ;
//Fire
PINFO
( " Fired all software synchronous outputs by software trigger. \n " ) ;
outl ( 0x8000 , instance - > single_reg ) ;
PDEBUG_REG ( " single_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > single_reg - instance - > reg_base ,
0x8000 ) ;
//Restore save settings
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
} else if ( ! mode ) { //Trigger outputs
/* //Remove channel from start list
outl ( sync_mask & ~ ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base , instance - > preload_reg - instance - > reg_base , sync_mask & ~ ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ) ;
*/
//Fire
PINFO ( " Software trigger. \n " ) ;
outl ( 0x8000 , instance - > single_reg ) ;
PDEBUG_REG ( " single_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > single_reg - instance - > reg_base ,
0x8000 ) ;
/* //Restore save settings
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base , instance - > preload_reg - instance - > reg_base , sync_mask ) ;
*/
}
/// @note This is mix-mode case. For now I do not have possibility to trigger first 4 channels (continous mode) and other (single) ones at once.
/// @note Because triggering is not working it can not be add to synchronous list. First 4 channels don't need this information, anyway.
* instance - > triggering_flags & = 0xFFFFFFF0 ;
} else { // No FIFO - Single mode
if ( flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS ) { //Fired all software synchronous outputs.
tmp = ~ ( * instance - > preload_flags | 0xFFFF0000 ) ;
PINFO
( " Fired all software synchronous outputs. mask:0x%08x \n " ,
tmp ) ;
tmp | = sync_mask & 0xFFFF0000 ;
// Add this channel to list
tmp & = ~ ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ;
//Fire
PINFO ( " Software trigger. \n " ) ;
outl ( tmp , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
tmp ) ;
//Restore save settings
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
//Set all as triggered.
* instance - > triggering_flags = 0x0 ;
} else if ( ! mode ) { // Add this channel to list
outl ( sync_mask &
~ ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ,
instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask & ~ ( ME6000_AO_SYNC_HOLD < <
instance - > ao_idx ) ) ;
//Fire
PINFO ( " Software trigger. \n " ) ;
//Restore save settings
outl ( sync_mask , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
sync_mask ) ;
//Set all as triggered.
* instance - > triggering_flags = 0x0 ;
}
}
spin_unlock ( instance - > preload_reg_lock ) ;
instance - > status = ao_status_single_run_wait ;
instance - > timeout . delay = delay ;
instance - > timeout . start_time = jiffies ;
instance - > ao_control_task_flag = 1 ;
queue_delayed_work ( instance - > me6000_workqueue ,
& instance - > ao_control_task , 1 ) ;
if ( ! ( flags & ME_IO_SINGLE_TYPE_WRITE_NONBLOCKING ) ) {
j = jiffies ;
//Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason.
wait_event_interruptible_timeout ( instance - > wait_queue ,
( instance - > status ! =
ao_status_single_run_wait ) ,
( delay ) ? delay +
1 : LONG_MAX ) ;
if ( instance - > status ! = ao_status_single_end ) {
PDEBUG ( " Single canceled. \n " ) ;
err = ME_ERRNO_CANCELLED ;
}
if ( signal_pending ( current ) ) {
PERROR ( " Wait on start of state machine interrupted. \n " ) ;
instance - > ao_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ao_control_task ) ;
ao_stop_immediately ( instance ) ;
instance - > status = ao_status_none ;
err = ME_ERRNO_SIGNAL ;
}
if ( ( delay ) & & ( ( jiffies - j ) > = delay ) ) {
if ( instance - > status = = ao_status_single_end ) {
PDEBUG ( " Timeout reached. \n " ) ;
} else if ( ( jiffies - j ) > delay ) {
PERROR
( " Timeout reached. Not handled by control task! \n " ) ;
ao_stop_immediately ( instance ) ;
} else {
PERROR
( " Timeout reached. Signal come but status is strange: %d \n " ,
instance - > status ) ;
ao_stop_immediately ( instance ) ;
}
instance - > ao_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ao_control_task ) ;
instance - > status = ao_status_single_end ;
err = ME_ERRNO_TIMEOUT ;
}
}
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_stream_config ( me_subdevice_t * subdevice ,
struct file * filep ,
meIOStreamConfig_t * config_list ,
int count ,
meIOStreamTrigger_t * trigger ,
int fifo_irq_threshold , int flags )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
uint32_t ctrl ;
unsigned long cpu_flags ;
uint64_t conv_ticks ;
unsigned int conv_start_ticks_low = trigger - > iConvStartTicksLow ;
unsigned int conv_start_ticks_high = trigger - > iConvStartTicksHigh ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) {
PERROR ( " Not a streaming ao. \n " ) ;
return ME_ERRNO_NOT_SUPPORTED ;
}
conv_ticks =
( uint64_t ) conv_start_ticks_low +
( ( uint64_t ) conv_start_ticks_high < < 32 ) ;
if ( flags &
~ ( ME_IO_STREAM_CONFIG_HARDWARE_ONLY |
ME_IO_STREAM_CONFIG_WRAPAROUND ) ) {
PERROR ( " Invalid flags. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( flags & ME_IO_STREAM_CONFIG_HARDWARE_ONLY ) {
2008-12-24 15:23:37 +00:00
if ( ! ( flags & ME_IO_STREAM_CONFIG_WRAPAROUND ) ) {
2008-10-31 23:39:12 +00:00
PERROR
( " Hardware ME_IO_STREAM_CONFIG_HARDWARE_ONLY has to be with ME_IO_STREAM_CONFIG_WRAPAROUND. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( ( trigger - > iAcqStopTrigType ! = ME_TRIG_TYPE_NONE )
| | ( trigger - > iScanStopTrigType ! = ME_TRIG_TYPE_NONE ) ) {
PERROR
( " Hardware wraparound mode must be in infinite mode. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
}
if ( count ! = 1 ) {
PERROR ( " Only 1 entry in config list acceptable. \n " ) ;
return ME_ERRNO_INVALID_CONFIG_LIST_COUNT ;
}
if ( config_list [ 0 ] . iChannel ! = 0 ) {
PERROR ( " Invalid channel number specified. \n " ) ;
return ME_ERRNO_INVALID_CHANNEL ;
}
if ( config_list [ 0 ] . iStreamConfig ! = 0 ) {
PERROR ( " Only one range available. \n " ) ;
return ME_ERRNO_INVALID_STREAM_CONFIG ;
}
if ( config_list [ 0 ] . iRef ! = ME_REF_AO_GROUND ) {
PERROR ( " Output is referenced to ground. \n " ) ;
return ME_ERRNO_INVALID_REF ;
}
if ( ( trigger - > iAcqStartTicksLow ! = 0 )
| | ( trigger - > iAcqStartTicksHigh ! = 0 ) ) {
PERROR
( " Invalid acquisition start trigger argument specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_START_ARG ;
}
if ( config_list [ 0 ] . iFlags ) {
PERROR ( " Invalid config list flag. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( ( trigger - > iAcqStartTrigType ! = ME_TRIG_TYPE_SW )
& & ( trigger - > iAcqStartTrigType ! = ME_TRIG_TYPE_EXT_DIGITAL ) ) {
PERROR ( " Invalid acquisition start trigger type specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE ;
}
if ( trigger - > iAcqStartTrigType = = ME_TRIG_TYPE_EXT_DIGITAL ) {
switch ( trigger - > iAcqStartTrigEdge ) {
case ME_TRIG_EDGE_RISING :
case ME_TRIG_EDGE_FALLING :
case ME_TRIG_EDGE_ANY :
break ;
default :
PERROR
( " Invalid acquisition start trigger edge specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE ;
}
}
if ( ( trigger - > iAcqStartTrigType = = ME_TRIG_TYPE_SW )
& & ( trigger - > iAcqStartTrigEdge ! = ME_TRIG_TYPE_NONE ) ) {
PERROR ( " Invalid acquisition start trigger edge specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE ;
}
if ( trigger - > iScanStartTrigType ! = ME_TRIG_TYPE_FOLLOW ) {
PERROR ( " Invalid scan start trigger type specified. \n " ) ;
return ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE ;
}
if ( trigger - > iConvStartTrigType ! = ME_TRIG_TYPE_TIMER ) {
PERROR ( " Invalid conv start trigger type specified. \n " ) ;
return ME_ERRNO_INVALID_CONV_START_TRIG_TYPE ;
}
if ( ( conv_ticks < ME6000_AO_MIN_CHAN_TICKS )
| | ( conv_ticks > ME6000_AO_MAX_CHAN_TICKS ) ) {
PERROR ( " Invalid conv start trigger argument specified. \n " ) ;
return ME_ERRNO_INVALID_CONV_START_ARG ;
}
if ( trigger - > iAcqStartTicksLow | | trigger - > iAcqStartTicksHigh ) {
PERROR ( " Invalid acq start trigger argument specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_START_ARG ;
}
if ( trigger - > iScanStartTicksLow | | trigger - > iScanStartTicksHigh ) {
PERROR ( " Invalid scan start trigger argument specified. \n " ) ;
return ME_ERRNO_INVALID_SCAN_START_ARG ;
}
switch ( trigger - > iScanStopTrigType ) {
case ME_TRIG_TYPE_NONE :
if ( trigger - > iScanStopCount ! = 0 ) {
PERROR ( " Invalid scan stop count specified. \n " ) ;
return ME_ERRNO_INVALID_SCAN_STOP_ARG ;
}
break ;
case ME_TRIG_TYPE_COUNT :
if ( flags & ME_IO_STREAM_CONFIG_WRAPAROUND ) {
if ( trigger - > iScanStopCount < = 0 ) {
PERROR ( " Invalid scan stop count specified. \n " ) ;
return ME_ERRNO_INVALID_SCAN_STOP_ARG ;
}
} else {
PERROR ( " The continous mode has not 'scan' contects. \n " ) ;
return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE ;
}
break ;
default :
PERROR ( " Invalid scan stop trigger type specified. \n " ) ;
return ME_ERRNO_INVALID_SCAN_STOP_TRIG_TYPE ;
}
switch ( trigger - > iAcqStopTrigType ) {
case ME_TRIG_TYPE_NONE :
if ( trigger - > iAcqStopCount ! = 0 ) {
PERROR ( " Invalid acq stop count specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_STOP_ARG ;
}
break ;
case ME_TRIG_TYPE_COUNT :
if ( trigger - > iScanStopTrigType ! = ME_TRIG_TYPE_NONE ) {
PERROR ( " Invalid acq stop trigger type specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE ;
}
if ( flags & ME_IO_STREAM_CONFIG_WRAPAROUND ) {
if ( trigger - > iAcqStopCount < = 0 ) {
PERROR
( " The continous mode has not 'scan' contects. \n " ) ;
return ME_ERRNO_INVALID_ACQ_STOP_ARG ;
}
}
// else
// {
// PERROR("Invalid acq stop trigger type specified.\n");
// return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE;
// }
break ;
default :
PERROR ( " Invalid acq stop trigger type specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE ;
}
switch ( trigger - > iAcqStartTrigChan ) {
case ME_TRIG_CHAN_DEFAULT :
case ME_TRIG_CHAN_SYNCHRONOUS :
break ;
default :
PERROR ( " Invalid acq start trigger channel specified. \n " ) ;
return ME_ERRNO_INVALID_ACQ_START_TRIG_CHAN ;
}
ME_SUBDEVICE_ENTER ;
//Stop device
//Cancel control task
PDEBUG ( " Cancel control task. idx=%d \n " , instance - > ao_idx ) ;
instance - > ao_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ao_control_task ) ;
//Check if state machine is stopped.
err = ao_stop_immediately ( instance ) ;
if ( err ) {
PERROR_CRITICAL ( " FSM IS BUSY! \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_SUBDEVICE_BUSY ;
}
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
//Reset control register. Block all actions. Disable IRQ. Disable FIFO.
ctrl = ME6000_AO_CTRL_BIT_IMMEDIATE_STOP | ME6000_AO_CTRL_BIT_STOP ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
//This is paranoic, but to be sure.
instance - > preloaded_count = 0 ;
instance - > data_count = 0 ;
instance - > circ_buf . head = 0 ;
instance - > circ_buf . tail = 0 ;
/* Set mode. */
if ( flags & ME_IO_STREAM_CONFIG_WRAPAROUND ) { //Wraparound
if ( flags & ME_IO_STREAM_CONFIG_HARDWARE_ONLY ) { //Hardware wraparound
PINFO ( " Hardware wraparound. \n " ) ;
ctrl | = ME6000_AO_MODE_WRAPAROUND ;
instance - > mode = ME6000_AO_HW_WRAP_MODE ;
} else { //Software wraparound
PINFO ( " Software wraparound. \n " ) ;
ctrl | = ME6000_AO_MODE_CONTINUOUS ;
instance - > mode = ME6000_AO_SW_WRAP_MODE ;
}
} else { //Continous
PINFO ( " Continous. \n " ) ;
ctrl | = ME6000_AO_MODE_CONTINUOUS ;
instance - > mode = ME6000_AO_CONTINOUS ;
}
//Set the trigger edge.
if ( trigger - > iAcqStartTrigType = = ME_TRIG_TYPE_EXT_DIGITAL ) { //Set the trigger type and edge for external trigger.
PINFO ( " External digital trigger. \n " ) ;
instance - > start_mode = ME6000_AO_EXT_TRIG ;
switch ( trigger - > iAcqStartTrigEdge ) {
case ME_TRIG_EDGE_RISING :
PINFO ( " Set the trigger edge: rising. \n " ) ;
instance - > ctrl_trg = 0x0 ;
break ;
case ME_TRIG_EDGE_FALLING :
PINFO ( " Set the trigger edge: falling. \n " ) ;
// ctrl |= ME6000_AO_CTRL_BIT_EX_TRIG_EDGE;
instance - > ctrl_trg = ME6000_AO_CTRL_BIT_EX_TRIG_EDGE ;
break ;
case ME_TRIG_EDGE_ANY :
PINFO ( " Set the trigger edge: both edges. \n " ) ;
// ctrl |= ME6000_AO_CTRL_BIT_EX_TRIG_EDGE | ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH;
instance - > ctrl_trg =
ME6000_AO_CTRL_BIT_EX_TRIG_EDGE |
ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH ;
break ;
}
} else {
PINFO ( " Internal software trigger. \n " ) ;
instance - > start_mode = 0 ;
}
//Set the stop mode and value.
if ( trigger - > iAcqStopTrigType = = ME_TRIG_TYPE_COUNT ) { //Amount of data
instance - > stop_mode = ME6000_AO_ACQ_STOP_MODE ;
instance - > stop_count = trigger - > iAcqStopCount ;
} else if ( trigger - > iScanStopTrigType = = ME_TRIG_TYPE_COUNT ) { //Amount of 'scans'
instance - > stop_mode = ME6000_AO_SCAN_STOP_MODE ;
instance - > stop_count = trigger - > iScanStopCount ;
} else { //Infinite
instance - > stop_mode = ME6000_AO_INF_STOP_MODE ;
instance - > stop_count = 0 ;
}
PINFO ( " Stop count: %d. \n " , instance - > stop_count ) ;
if ( trigger - > iAcqStartTrigChan = = ME_TRIG_CHAN_SYNCHRONOUS ) { //Synchronous start
instance - > start_mode | = ME6000_AO_SYNC_HOLD ;
if ( trigger - > iAcqStartTrigType = = ME_TRIG_TYPE_EXT_DIGITAL ) { //Externaly triggered
PINFO ( " Synchronous start. Externaly trigger active. \n " ) ;
instance - > start_mode | = ME6000_AO_SYNC_EXT_TRIG ;
}
# ifdef MEDEBUG_INFO
else {
PINFO
( " Synchronous start. Externaly trigger dissabled. \n " ) ;
}
# endif
}
//Set speed
outl ( conv_ticks - 2 , instance - > timer_reg ) ;
PDEBUG_REG ( " timer_reg outl(0x%lX+0x%lX)=0x%llx \n " , instance - > reg_base ,
instance - > timer_reg - instance - > reg_base , conv_ticks - 2 ) ;
instance - > hardware_stop_delay = ( int ) ( conv_ticks * HZ ) / ME6000_AO_BASE_FREQUENCY ; //<== MUST be with cast!
// Write the control word
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
//Set status.
instance - > status = ao_status_stream_configured ;
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_stream_new_values ( me_subdevice_t * subdevice ,
struct file * filep ,
int time_out , int * count , int flags )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
long t = 0 ;
long j ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) {
PERROR ( " Not a streaming ao. \n " ) ;
return ME_ERRNO_NOT_SUPPORTED ;
}
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( ! instance - > circ_buf . buf ) {
PERROR ( " Circular buffer not exists. \n " ) ;
return ME_ERRNO_INTERNAL ;
}
if ( time_out < 0 ) {
PERROR ( " Invalid time_out specified. \n " ) ;
return ME_ERRNO_INVALID_TIMEOUT ;
}
ME_SUBDEVICE_ENTER ;
if ( me_circ_buf_space ( & instance - > circ_buf ) ) { //The buffer is NOT full.
* count = me_circ_buf_space ( & instance - > circ_buf ) ;
} else { //The buffer is full.
if ( time_out ) {
t = ( time_out * HZ ) / 1000 ;
if ( t = = 0 )
t = 1 ;
} else { //Max time.
t = LONG_MAX ;
}
* count = 0 ;
j = jiffies ;
//Only runing process will interrupt this call. Interrupts are when FIFO HF is signaled.
wait_event_interruptible_timeout ( instance - > wait_queue ,
( ( me_circ_buf_space
( & instance - > circ_buf ) )
| | ! ( inl ( instance - > status_reg )
&
ME6000_AO_STATUS_BIT_FSM ) ) ,
t ) ;
if ( ! ( inl ( instance - > status_reg ) & ME6000_AO_STATUS_BIT_FSM ) ) {
PERROR ( " AO subdevice is not running. \n " ) ;
err = ME_ERRNO_SUBDEVICE_NOT_RUNNING ;
} else if ( signal_pending ( current ) ) {
PERROR ( " Wait on values interrupted from signal. \n " ) ;
instance - > status = ao_status_none ;
ao_stop_immediately ( instance ) ;
err = ME_ERRNO_SIGNAL ;
} else if ( ( jiffies - j ) > = t ) {
PERROR ( " Wait on values timed out. \n " ) ;
err = ME_ERRNO_TIMEOUT ;
} else { //Uff... all is good. Inform user about empty space.
* count = me_circ_buf_space ( & instance - > circ_buf ) ;
}
}
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_stream_start ( me_subdevice_t * subdevice ,
struct file * filep ,
int start_mode , int time_out , int flags )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
unsigned long cpu_flags = 0 ;
uint32_t status ;
uint32_t ctrl ;
uint32_t synch ;
int count = 0 ;
int circ_buffer_count ;
unsigned long ref ;
unsigned long delay = 0 ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) {
PERROR ( " Not a streaming ao. \n " ) ;
return ME_ERRNO_NOT_SUPPORTED ;
}
if ( flags & ~ ME_IO_STREAM_START_TYPE_TRIG_SYNCHRONOUS ) {
PERROR ( " Invalid flags. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( time_out < 0 ) {
PERROR ( " Invalid timeout specified. \n " ) ;
return ME_ERRNO_INVALID_TIMEOUT ;
}
if ( ( start_mode ! = ME_START_MODE_BLOCKING )
& & ( start_mode ! = ME_START_MODE_NONBLOCKING ) ) {
PERROR ( " Invalid start mode specified. \n " ) ;
return ME_ERRNO_INVALID_START_MODE ;
}
if ( time_out ) {
delay = ( time_out * HZ ) / 1000 ;
if ( delay = = 0 )
delay = 1 ;
}
switch ( instance - > status ) { //Checking actual mode.
case ao_status_stream_configured :
case ao_status_stream_end :
//Correct modes!
break ;
//The device is in wrong mode.
case ao_status_none :
case ao_status_single_configured :
case ao_status_single_run_wait :
case ao_status_single_run :
case ao_status_single_end_wait :
PERROR
( " Subdevice must be preinitialize correctly for streaming. \n " ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
case ao_status_stream_fifo_error :
case ao_status_stream_buffer_error :
case ao_status_stream_error :
PDEBUG ( " Before restart broke stream 'STOP' must be caled. \n " ) ;
return ME_STATUS_ERROR ;
case ao_status_stream_run_wait :
case ao_status_stream_run :
case ao_status_stream_end_wait :
PDEBUG ( " Stream is already working. \n " ) ;
return ME_ERRNO_SUBDEVICE_BUSY ;
default :
instance - > status = ao_status_stream_error ;
PERROR_CRITICAL ( " Status is in wrong state! \n " ) ;
return ME_ERRNO_INTERNAL ;
}
ME_SUBDEVICE_ENTER ;
if ( instance - > mode = = ME6000_AO_CONTINOUS ) { //Continous
instance - > circ_buf . tail + = instance - > preloaded_count ;
instance - > circ_buf . tail & = instance - > circ_buf . mask ;
}
circ_buffer_count = me_circ_buf_values ( & instance - > circ_buf ) ;
if ( ! circ_buffer_count & & ! instance - > preloaded_count ) { //No values in buffer
ME_SUBDEVICE_EXIT ;
PERROR ( " No values in buffer! \n " ) ;
return ME_ERRNO_LACK_OF_RESOURCES ;
}
//Cancel control task
PDEBUG ( " Cancel control task. idx=%d \n " , instance - > ao_idx ) ;
instance - > ao_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ao_control_task ) ;
//Stop device
err = ao_stop_immediately ( instance ) ;
if ( err ) {
PERROR_CRITICAL ( " FSM IS BUSY! \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_SUBDEVICE_BUSY ;
}
//Set values for single_read()
instance - > single_value = ME6000_AO_MAX_DATA + 1 ;
instance - > single_value_in_fifo = ME6000_AO_MAX_DATA + 1 ;
//Setting stop points
if ( instance - > stop_mode = = ME6000_AO_SCAN_STOP_MODE ) {
instance - > stop_data_count =
instance - > stop_count * circ_buffer_count ;
} else {
instance - > stop_data_count = instance - > stop_count ;
}
if ( ( instance - > stop_data_count ! = 0 )
& & ( instance - > stop_data_count < circ_buffer_count ) ) {
PERROR ( " More data in buffer than previously set limit! \n " ) ;
}
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
//Check FIFO
if ( ! ( ctrl & ME6000_AO_CTRL_BIT_ENABLE_FIFO ) ) { //FIFO wasn't enabeled. Do it. <= This should be done by user call with ME_WRITE_MODE_PRELOAD
PINFO ( " Enableing FIFO. \n " ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_FIFO ;
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
instance - > preloaded_count = 0 ;
instance - > data_count = 0 ;
} else { //Block IRQ
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
}
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
//Fill FIFO <= Generaly this should be done by user pre-load call but this is second place to do it.
status = inl ( instance - > status_reg ) ;
if ( ! ( status & ME6000_AO_STATUS_BIT_EF ) ) { //FIFO empty
if ( instance - > stop_data_count ! = 0 ) {
count = ME6000_AO_FIFO_COUNT ;
} else {
count =
( ME6000_AO_FIFO_COUNT <
instance - >
stop_data_count ) ? ME6000_AO_FIFO_COUNT :
instance - > stop_data_count ;
}
//Copy data
count =
ao_write_data ( instance , count , instance - > preloaded_count ) ;
if ( count < 0 ) { //This should never happend!
PERROR_CRITICAL ( " COPY FINISH WITH ERROR! \n " ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_INTERNAL ;
}
}
//Set pre-load features.
spin_lock ( instance - > preload_reg_lock ) ;
synch = inl ( instance - > preload_reg ) ;
synch & =
~ ( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < < instance - >
ao_idx ) ;
synch | =
( instance - > start_mode & ~ ME6000_AO_EXT_TRIG ) < < instance - > ao_idx ;
outl ( synch , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > preload_reg - instance - > reg_base , synch ) ;
spin_unlock ( instance - > preload_reg_lock ) ;
//Default count is '0'
if ( instance - > mode = = ME6000_AO_CONTINOUS ) { //Continous
instance - > preloaded_count = 0 ;
instance - > circ_buf . tail + = count ;
instance - > circ_buf . tail & = instance - > circ_buf . mask ;
} else { //Wraparound
instance - > preloaded_count + = count ;
instance - > data_count + = count ;
//Special case: Infinite wraparound with less than FIFO datas always should runs in hardware mode.
if ( ( instance - > stop_mode = = ME6000_AO_INF_STOP_MODE )
& & ( circ_buffer_count < = ME6000_AO_FIFO_COUNT ) ) { //Change to hardware wraparound
PDEBUG
( " Changeing mode from software wraparound to hardware wraparound. \n " ) ;
//Copy all data
count =
ao_write_data ( instance , circ_buffer_count ,
instance - > preloaded_count ) ;
ctrl & = ~ ME6000_AO_CTRL_MODE_MASK ;
ctrl | = ME6000_AO_MODE_WRAPAROUND ;
}
if ( instance - > preloaded_count = = me_circ_buf_values ( & instance - > circ_buf ) ) { //Reset position indicator.
instance - > preloaded_count = 0 ;
} else if ( instance - > preloaded_count > me_circ_buf_values ( & instance - > circ_buf ) ) { //This should never happend!
PERROR_CRITICAL
( " PRELOADED MORE VALUES THAN ARE IN BUFFER! \n " ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_INTERNAL ;
}
}
//Set status to 'wait for start'
instance - > status = ao_status_stream_run_wait ;
status = inl ( instance - > status_reg ) ;
//Start state machine and interrupts
2009-01-07 22:31:57 +00:00
PINFO ( " <%s:%d> Start state machine. \n " , __func__ , __LINE__ ) ;
2008-10-31 23:39:12 +00:00
ctrl & = ~ ( ME6000_AO_CTRL_BIT_STOP | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP ) ;
if ( instance - > start_mode = = ME6000_AO_EXT_TRIG ) {
PDEBUG ( " DIGITAL TRIGGER \n " ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ;
}
if ( ! ( status & ME6000_AO_STATUS_BIT_HF ) ) { //More than half!
if ( ( ctrl & ME6000_AO_CTRL_MODE_MASK ) = = ME6000_AO_MODE_CONTINUOUS ) { //Enable IRQ only when hardware_continous is set and FIFO is more than half
2009-01-07 22:31:57 +00:00
PINFO ( " <%s:%d> Start interrupts. \n " , __func__ ,
2008-10-31 23:39:12 +00:00
__LINE__ ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
}
}
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
//Trigger output
2009-01-07 22:31:57 +00:00
PINFO ( " <%s> start mode= 0x%x %s \n " , __func__ , instance - > start_mode ,
2008-10-31 23:39:12 +00:00
( flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS ) ? " SYNCHRONOUS " :
" " ) ;
if ( flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS ) { //Trigger outputs
spin_lock ( instance - > preload_reg_lock ) ;
synch = inl ( instance - > preload_reg ) ;
//Add channel to start list
outl ( synch | ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ,
instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
synch | ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ) ;
//Fire
PINFO
( " Fired all software synchronous outputs by software trigger. \n " ) ;
outl ( 0x8000 , instance - > single_reg ) ;
PDEBUG_REG ( " single_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > single_reg - instance - > reg_base , 0x8000 ) ;
//Restore save settings
outl ( synch , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base , synch ) ;
spin_unlock ( instance - > preload_reg_lock ) ;
} else if ( ! instance - > start_mode ) { //Trigger outputs
/*
spin_lock ( instance - > preload_reg_lock ) ;
synch = inl ( instance - > preload_reg ) ;
//Remove channel from start list
outl ( synch & ~ ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base , instance - > preload_reg - instance - > reg_base , synch & ~ ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ) ;
*/
//Fire
PINFO ( " Software trigger. \n " ) ;
outl ( 0x8000 , instance - > single_reg ) ;
PDEBUG_REG ( " single_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > single_reg - instance - > reg_base , 0x8000 ) ;
/*
//Restore save settings
outl ( synch , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base , instance - > preload_reg - instance - > reg_base , synch ) ;
spin_unlock ( instance - > preload_reg_lock ) ;
*/
}
// Set control task's timeout
instance - > timeout . delay = delay ;
instance - > timeout . start_time = jiffies ;
if ( status & ME6000_AO_STATUS_BIT_HF ) { //Less than half but not empty!
PINFO ( " Less than half. \n " ) ;
if ( instance - > stop_data_count = = 0 ) {
count = ME6000_AO_FIFO_COUNT / 2 ;
} else {
count =
( ( ME6000_AO_FIFO_COUNT / 2 ) <
instance - > stop_data_count ) ? ME6000_AO_FIFO_COUNT /
2 : instance - > stop_data_count ;
}
//Copy data
count =
ao_write_data ( instance , count , instance - > preloaded_count ) ;
if ( count < 0 ) { //This should never happend!
PERROR_CRITICAL ( " COPY FINISH WITH ERROR! \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_INTERNAL ;
}
if ( instance - > mode = = ME6000_AO_CONTINOUS ) { //Continous
instance - > circ_buf . tail + = count ;
instance - > circ_buf . tail & = instance - > circ_buf . mask ;
} else { //Wraparound
instance - > data_count + = count ;
instance - > preloaded_count + = count ;
if ( instance - > preloaded_count = = me_circ_buf_values ( & instance - > circ_buf ) ) { //Reset position indicator.
instance - > preloaded_count = 0 ;
} else if ( instance - > preloaded_count > me_circ_buf_values ( & instance - > circ_buf ) ) { //This should never happend!
PERROR_CRITICAL
( " PRELOADED MORE VALUES THAN ARE IN BUFFER! \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_INTERNAL ;
}
}
status = inl ( instance - > status_reg ) ;
if ( ! ( status & ME6000_AO_STATUS_BIT_HF ) ) { //More than half!
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
2009-01-07 22:31:57 +00:00
PINFO ( " <%s:%d> Start interrupts. \n " , __func__ ,
2008-10-31 23:39:12 +00:00
__LINE__ ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
ctrl ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
}
}
//Special case: Limited wraparound with less than HALF FIFO datas need work around to generate first interrupt.
if ( ( instance - > stop_mode ! = ME6000_AO_INF_STOP_MODE )
& & ( instance - > mode = = ME6000_AO_SW_WRAP_MODE )
& & ( circ_buffer_count < = ( ME6000_AO_FIFO_COUNT / 2 ) ) ) { //Put more data to FIFO
PINFO ( " Limited wraparound with less than HALF FIFO datas. \n " ) ;
if ( instance - > preloaded_count ) { //This should never happend!
PERROR_CRITICAL
( " ERROR WHEN LOADING VALUES FOR WRAPAROUND! \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_INTERNAL ;
}
while ( instance - > stop_data_count > instance - > data_count ) { //Maximum data not set jet.
//Copy to buffer
if ( circ_buffer_count ! = ao_write_data ( instance , circ_buffer_count , 0 ) ) { //This should never happend!
PERROR_CRITICAL
( " ERROR WHEN LOADING VALUES FOR WRAPAROUND! \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_INTERNAL ;
}
instance - > data_count + = circ_buffer_count ;
if ( ! ( ( status = inl ( instance - > status_reg ) ) & ME6000_AO_STATUS_BIT_HF ) ) { //FIFO is more than half. Enable IRQ and end copy.
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
spin_lock_irqsave ( & instance - > subdevice_lock ,
cpu_flags ) ;
PINFO ( " <%s:%d> Start interrupts. \n " ,
2009-01-07 22:31:57 +00:00
__func__ , __LINE__ ) ;
2008-10-31 23:39:12 +00:00
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg -
instance - > reg_base , ctrl ) ;
spin_unlock_irqrestore ( & instance - >
subdevice_lock ,
cpu_flags ) ;
break ;
}
}
}
// Schedule control task
instance - > ao_control_task_flag = 1 ;
queue_delayed_work ( instance - > me6000_workqueue ,
& instance - > ao_control_task , 1 ) ;
if ( start_mode = = ME_START_MODE_BLOCKING ) { //Wait for start.
ref = jiffies ;
//Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason.
wait_event_interruptible_timeout ( instance - > wait_queue ,
( instance - > status ! =
ao_status_stream_run_wait ) ,
( delay ) ? delay +
1 : LONG_MAX ) ;
if ( ( instance - > status ! = ao_status_stream_run )
& & ( instance - > status ! = ao_status_stream_end ) ) {
PDEBUG ( " Starting stream canceled. %d \n " ,
instance - > status ) ;
err = ME_ERRNO_CANCELLED ;
}
if ( signal_pending ( current ) ) {
PERROR ( " Wait on start of state machine interrupted. \n " ) ;
instance - > status = ao_status_none ;
ao_stop_immediately ( instance ) ;
err = ME_ERRNO_SIGNAL ;
}
if ( ( delay ) & & ( ( jiffies - ref ) > = delay ) ) {
if ( instance - > status ! = ao_status_stream_run ) {
if ( instance - > status = = ao_status_stream_end ) {
PDEBUG ( " Timeout reached. \n " ) ;
} else if ( ( jiffies - ref ) > delay ) {
PERROR
( " Timeout reached. Not handled by control task! \n " ) ;
ao_stop_immediately ( instance ) ;
} else {
PERROR
( " Timeout reached. Signal come but status is strange: %d \n " ,
instance - > status ) ;
ao_stop_immediately ( instance ) ;
}
instance - > ao_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ao_control_task ) ;
instance - > status = ao_status_stream_end ;
err = ME_ERRNO_TIMEOUT ;
}
}
}
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_stream_status ( me_subdevice_t * subdevice ,
struct file * filep ,
int wait ,
int * status , int * values , int flags )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) {
PERROR ( " Not a streaming ao. \n " ) ;
return ME_ERRNO_NOT_SUPPORTED ;
}
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( ( wait ! = ME_WAIT_NONE ) & & ( wait ! = ME_WAIT_IDLE ) ) {
PERROR ( " Invalid wait argument specified. \n " ) ;
* status = ME_STATUS_INVALID ;
return ME_ERRNO_INVALID_WAIT ;
}
ME_SUBDEVICE_ENTER ;
switch ( instance - > status ) {
case ao_status_single_configured :
case ao_status_single_end :
case ao_status_stream_configured :
case ao_status_stream_end :
case ao_status_stream_fifo_error :
case ao_status_stream_buffer_error :
case ao_status_stream_error :
* status = ME_STATUS_IDLE ;
break ;
case ao_status_single_run_wait :
case ao_status_single_run :
case ao_status_single_end_wait :
case ao_status_stream_run_wait :
case ao_status_stream_run :
case ao_status_stream_end_wait :
* status = ME_STATUS_BUSY ;
break ;
case ao_status_none :
default :
* status =
( inl ( instance - > status_reg ) & ME6000_AO_STATUS_BIT_FSM ) ?
ME_STATUS_BUSY : ME_STATUS_IDLE ;
break ;
}
if ( ( wait = = ME_WAIT_IDLE ) & & ( * status = = ME_STATUS_BUSY ) ) {
//Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason.
wait_event_interruptible_timeout ( instance - > wait_queue ,
( ( instance - > status ! =
ao_status_single_run_wait )
& & ( instance - > status ! =
ao_status_single_run )
& & ( instance - > status ! =
ao_status_single_end_wait )
& & ( instance - > status ! =
ao_status_stream_run_wait )
& & ( instance - > status ! =
ao_status_stream_run )
& & ( instance - > status ! =
ao_status_stream_end_wait ) ) ,
LONG_MAX ) ;
if ( instance - > status ! = ao_status_stream_end ) {
PDEBUG ( " Wait for IDLE canceled. %d \n " ,
instance - > status ) ;
err = ME_ERRNO_CANCELLED ;
}
if ( signal_pending ( current ) ) {
PERROR ( " Wait for IDLE interrupted. \n " ) ;
instance - > status = ao_status_none ;
ao_stop_immediately ( instance ) ;
err = ME_ERRNO_SIGNAL ;
}
* status = ME_STATUS_IDLE ;
}
* values = me_circ_buf_space ( & instance - > circ_buf ) ;
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_stream_stop ( me_subdevice_t * subdevice ,
struct file * filep ,
int stop_mode , int flags )
{ /// @note Stop work and empty buffer and FIFO
int err = ME_ERRNO_SUCCESS ;
me6000_ao_subdevice_t * instance ;
unsigned long cpu_flags ;
volatile uint32_t ctrl ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( flags & ~ ME_IO_STREAM_STOP_PRESERVE_BUFFERS ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( ( stop_mode ! = ME_STOP_MODE_IMMEDIATE )
& & ( stop_mode ! = ME_STOP_MODE_LAST_VALUE ) ) {
PERROR ( " Invalid stop mode specified. \n " ) ;
return ME_ERRNO_INVALID_STOP_MODE ;
}
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) {
PERROR ( " Not a streaming ao. \n " ) ;
return ME_ERRNO_NOT_SUPPORTED ;
}
if ( instance - > status < ao_status_stream_configured ) {
//There is nothing to stop!
PERROR ( " Subdevice not in streaming mode. %d \n " ,
instance - > status ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
}
ME_SUBDEVICE_ENTER ;
//Mark as stopping. => Software stop.
instance - > status = ao_status_stream_end_wait ;
if ( stop_mode = = ME_STOP_MODE_IMMEDIATE ) { //Stopped now!
err = ao_stop_immediately ( instance ) ;
} else if ( stop_mode = = ME_STOP_MODE_LAST_VALUE ) {
ctrl = inl ( instance - > ctrl_reg ) & ME6000_AO_CTRL_MODE_MASK ;
if ( ctrl = = ME6000_AO_MODE_WRAPAROUND ) { //Hardware wraparound => Hardware stop.
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | = ME6000_AO_CTRL_BIT_STOP ;
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
ctrl ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
}
//Only runing process will interrupt this call. Events are signaled when status change. Extra timeout add for safe reason.
wait_event_interruptible_timeout ( instance - > wait_queue ,
( instance - > status ! =
ao_status_stream_end_wait ) ,
LONG_MAX ) ;
if ( instance - > status ! = ao_status_stream_end ) {
PDEBUG ( " Stopping stream canceled. \n " ) ;
err = ME_ERRNO_CANCELLED ;
}
if ( signal_pending ( current ) ) {
PERROR ( " Stopping stream interrupted. \n " ) ;
instance - > status = ao_status_none ;
ao_stop_immediately ( instance ) ;
err = ME_ERRNO_SIGNAL ;
}
}
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | = ME6000_AO_CTRL_BIT_STOP | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP ;
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
if ( ! flags ) { //Reset FIFO
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_FIFO ;
}
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
if ( ! flags ) { //Reset software buffer
instance - > circ_buf . head = 0 ;
instance - > circ_buf . tail = 0 ;
instance - > preloaded_count = 0 ;
instance - > data_count = 0 ;
}
ME_SUBDEVICE_EXIT ;
return err ;
}
static int me6000_ao_io_stream_write ( me_subdevice_t * subdevice ,
struct file * filep ,
int write_mode ,
int * values , int * count , int flags )
{
int err = ME_ERRNO_SUCCESS ;
me6000_ao_subdevice_t * instance ;
unsigned long cpu_flags = 0 ;
uint32_t reg_copy ;
int copied_from_user = 0 ;
int left_to_copy_from_user = * count ;
int copied_values ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
//Checking arguments
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) {
PERROR ( " Not a streaming ao. \n " ) ;
return ME_ERRNO_NOT_SUPPORTED ;
}
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( * count < = 0 ) {
PERROR ( " Invalid count of values specified. \n " ) ;
return ME_ERRNO_INVALID_VALUE_COUNT ;
}
if ( values = = NULL ) {
PERROR ( " Invalid address of values specified. \n " ) ;
return ME_ERRNO_INVALID_POINTER ;
}
if ( ( instance - > status = = ao_status_none ) | | ( instance - > status = = ao_status_single_configured ) ) { //The device is in single mode.
PERROR
( " Subdevice must be preinitialize correctly for streaming. \n " ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
}
switch ( write_mode ) {
case ME_WRITE_MODE_PRELOAD :
//Device must be stopped.
if ( ( instance - > status ! = ao_status_stream_configured )
& & ( instance - > status ! = ao_status_stream_end ) ) {
PERROR
( " Subdevice mustn't be runing when 'pre-load' mode is used. \n " ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
}
break ;
case ME_WRITE_MODE_NONBLOCKING :
case ME_WRITE_MODE_BLOCKING :
/// @note In blocking mode: When device is not runing and there is not enought space call will blocked up!
/// @note Some other thread must empty buffer by strating engine.
break ;
default :
PERROR ( " Invalid write mode specified. \n " ) ;
return ME_ERRNO_INVALID_WRITE_MODE ;
}
if ( instance - > mode & ME6000_AO_WRAP_MODE ) { //Wraparound mode. Device must be stopped.
if ( ( instance - > status ! = ao_status_stream_configured )
& & ( instance - > status ! = ao_status_stream_end ) ) {
PERROR
( " Subdevice mustn't be runing when 'pre-load' mode is used. \n " ) ;
return ME_ERRNO_INVALID_WRITE_MODE ;
}
}
if ( ( instance - > mode = = ME6000_AO_HW_WRAP_MODE )
& & ( write_mode ! = ME_WRITE_MODE_PRELOAD ) ) {
/*
PERROR ( " Only 'pre-load' write is acceptable in hardware wraparound mode. \n " ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
*/
//This is transparent for user.
PDEBUG ( " Changing write_mode to ME_WRITE_MODE_PRELOAD. \n " ) ;
write_mode = ME_WRITE_MODE_PRELOAD ;
}
ME_SUBDEVICE_ENTER ;
if ( write_mode = = ME_WRITE_MODE_PRELOAD ) { //Init enviroment - preload
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
reg_copy = inl ( instance - > ctrl_reg ) ;
//Check FIFO
if ( ! ( reg_copy & ME6000_AO_CTRL_BIT_ENABLE_FIFO ) ) { //FIFO not active. Enable it.
reg_copy | = ME6000_AO_CTRL_BIT_ENABLE_FIFO ;
outl ( reg_copy , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
reg_copy ) ;
instance - > preloaded_count = 0 ;
}
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
}
while ( 1 ) {
//Copy to buffer. This step is common for all modes.
copied_from_user =
ao_get_data_from_user ( instance , left_to_copy_from_user ,
values + ( * count -
left_to_copy_from_user ) ) ;
left_to_copy_from_user - = copied_from_user ;
reg_copy = inl ( instance - > status_reg ) ;
if ( ( instance - > status = = ao_status_stream_run ) & & ! ( reg_copy & ME6000_AO_STATUS_BIT_FSM ) ) { //BROKEN PIPE! The state machine is stoped but logical status show that should be working.
PERROR ( " Broken pipe in write. \n " ) ;
err = ME_ERRNO_SUBDEVICE_NOT_RUNNING ;
break ;
}
if ( ( instance - > status = = ao_status_stream_run ) & & ( instance - > mode = = ME6000_AO_CONTINOUS ) & & ( reg_copy & ME6000_AO_STATUS_BIT_HF ) ) { //Continous mode runing and data are below half!
// Block interrupts.
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
reg_copy = inl ( instance - > ctrl_reg ) ;
reg_copy & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
outl ( reg_copy , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
reg_copy ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
//Fast copy
copied_values =
ao_write_data ( instance , ME6000_AO_FIFO_COUNT / 2 ,
0 ) ;
if ( copied_values > 0 ) {
instance - > circ_buf . tail + = copied_values ;
instance - > circ_buf . tail & =
instance - > circ_buf . mask ;
continue ;
}
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
// Activate interrupts.
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
reg_copy = inl ( instance - > ctrl_reg ) ;
reg_copy | = ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
outl ( reg_copy , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
reg_copy ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
if ( copied_values = = 0 ) { //This was checked and never should happend!
PERROR_CRITICAL ( " COPY FINISH WITH 0! \n " ) ;
}
if ( copied_values < 0 ) { //This was checked and never should happend!
PERROR_CRITICAL ( " COPY FINISH WITH ERROR! \n " ) ;
instance - > status = ao_status_stream_fifo_error ;
err = ME_ERRNO_FIFO_BUFFER_OVERFLOW ;
break ;
}
}
if ( ! left_to_copy_from_user ) { //All datas were copied.
break ;
} else { //Not all datas were copied.
if ( instance - > mode & ME6000_AO_WRAP_MODE ) { //Error too much datas! Wraparound is limited in size!
PERROR
( " Too much data for wraparound mode! Exceeded size of %ld. \n " ,
ME6000_AO_CIRC_BUF_COUNT - 1 ) ;
err = ME_ERRNO_RING_BUFFER_OVERFLOW ;
break ;
}
if ( write_mode ! = ME_WRITE_MODE_BLOCKING ) { //Non blocking calls
break ;
}
wait_event_interruptible ( instance - > wait_queue ,
me_circ_buf_space ( & instance - >
circ_buf ) ) ;
if ( signal_pending ( current ) ) {
PERROR ( " Writing interrupted by signal. \n " ) ;
instance - > status = ao_status_none ;
ao_stop_immediately ( instance ) ;
err = ME_ERRNO_SIGNAL ;
break ;
}
if ( instance - > status = = ao_status_none ) { //Reset
PERROR ( " Writing interrupted by reset. \n " ) ;
err = ME_ERRNO_CANCELLED ;
break ;
}
}
}
if ( write_mode = = ME_WRITE_MODE_PRELOAD ) { //Copy data to FIFO - preload
copied_values =
ao_write_data_pooling ( instance , ME6000_AO_FIFO_COUNT ,
instance - > preloaded_count ) ;
instance - > preloaded_count + = copied_values ;
instance - > data_count + = copied_values ;
if ( ( instance - > mode = = ME6000_AO_HW_WRAP_MODE )
& & ( me_circ_buf_values ( & instance - > circ_buf ) >
ME6000_AO_FIFO_COUNT ) ) {
PERROR
( " Too much data for hardware wraparound mode! Exceeded size of %d. \n " ,
ME6000_AO_FIFO_COUNT ) ;
err = ME_ERRNO_FIFO_BUFFER_OVERFLOW ;
}
}
* count = * count - left_to_copy_from_user ;
ME_SUBDEVICE_EXIT ;
return err ;
}
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
static irqreturn_t me6000_ao_isr ( int irq , void * dev_id )
# else
static irqreturn_t me6000_ao_isr ( int irq , void * dev_id , struct pt_regs * regs )
# endif
{
me6000_ao_subdevice_t * instance = dev_id ;
uint32_t irq_status ;
uint32_t ctrl ;
uint32_t status ;
int count = 0 ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( irq ! = instance - > irq ) {
PERROR ( " Incorrect interrupt num: %d. \n " , irq ) ;
return IRQ_NONE ;
}
irq_status = inl ( instance - > irq_status_reg ) ;
if ( ! ( irq_status & ( ME6000_IRQ_STATUS_BIT_AO_HF < < instance - > ao_idx ) ) ) {
PINFO ( " %ld Shared interrupt. %s(): ID=%d: status_reg=0x%04X \n " ,
2009-01-07 22:31:57 +00:00
jiffies , __func__ , instance - > ao_idx , irq_status ) ;
2008-10-31 23:39:12 +00:00
return IRQ_NONE ;
}
if ( ! instance - > circ_buf . buf ) {
instance - > status = ao_status_stream_error ;
PERROR_CRITICAL ( " CIRCULAR BUFFER NOT EXISTS! \n " ) ;
//Block interrupts. Stop machine.
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
ctrl | =
ME6000_AO_CTRL_BIT_IMMEDIATE_STOP | ME6000_AO_CTRL_BIT_STOP ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
//Inform user
wake_up_interruptible_all ( & instance - > wait_queue ) ;
return IRQ_HANDLED ;
}
status = inl ( instance - > status_reg ) ;
if ( ! ( status & ME6000_AO_STATUS_BIT_FSM ) ) { //Too late. Not working! END? BROKEN PIPE?
/// @note Error checking was moved to separate task.
PDEBUG ( " Interrupt come but ISM is not working! \n " ) ;
//Block interrupts. Stop machine.
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
ctrl | =
ME6000_AO_CTRL_BIT_STOP | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
/// @note User notification was also moved to separate task.
return IRQ_HANDLED ;
}
//General procedure. Process more datas.
# ifdef MEDEBUG_DEBUG
if ( ! me_circ_buf_values ( & instance - > circ_buf ) ) { //Buffer is empty!
PDEBUG ( " Circular buffer empty! \n " ) ;
}
# endif
//Check FIFO
if ( status & ME6000_AO_STATUS_BIT_HF ) { //OK less than half
//Block interrupts
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
do {
//Calculate how many should be copied.
count =
( instance - > stop_data_count ) ? instance - >
stop_data_count -
instance - > data_count : ME6000_AO_FIFO_COUNT / 2 ;
if ( ME6000_AO_FIFO_COUNT / 2 < count ) {
count = ME6000_AO_FIFO_COUNT / 2 ;
}
//Copy data
if ( instance - > mode = = ME6000_AO_CONTINOUS ) { //Continous
count = ao_write_data ( instance , count , 0 ) ;
if ( count > 0 ) {
instance - > circ_buf . tail + = count ;
instance - > circ_buf . tail & =
instance - > circ_buf . mask ;
instance - > data_count + = count ;
if ( ( instance - > status = = ao_status_stream_end_wait ) & & ! me_circ_buf_values ( & instance - > circ_buf ) ) { //Stoping. Whole buffer was copied.
break ;
}
}
} else if ( ( instance - > mode = = ME6000_AO_SW_WRAP_MODE ) & & ( ( ctrl & ME6000_AO_CTRL_MODE_MASK ) = = ME6000_AO_MODE_CONTINUOUS ) ) { //Wraparound (software)
if ( instance - > status = = ao_status_stream_end_wait ) { //We stoping => Copy to the end of the buffer.
count =
ao_write_data ( instance , count , 0 ) ;
} else { //Copy in wraparound mode.
count =
ao_write_data_wraparound ( instance ,
count ,
instance - >
preloaded_count ) ;
}
if ( count > 0 ) {
instance - > data_count + = count ;
instance - > preloaded_count + = count ;
instance - > preloaded_count % =
me_circ_buf_values ( & instance - >
circ_buf ) ;
if ( ( instance - > status = = ao_status_stream_end_wait ) & & ! instance - > preloaded_count ) { //Stoping. Whole buffer was copied.
break ;
}
}
}
if ( ( count < = 0 ) | | ( instance - > stop_data_count & & ( instance - > stop_data_count < = instance - > data_count ) ) ) { //End of work.
break ;
}
} //Repeat if still is under half fifo
while ( ( status =
inl ( instance - > status_reg ) ) & ME6000_AO_STATUS_BIT_HF ) ;
//Unblock interrupts
ctrl = inl ( instance - > ctrl_reg ) ;
if ( count > = 0 ) { //Copy was successful.
if ( instance - > stop_data_count & & ( instance - > stop_data_count < = instance - > data_count ) ) { //Finishing work. No more interrupts.
PDEBUG ( " Finishing work. Interrupt disabled. \n " ) ;
instance - > status = ao_status_stream_end_wait ;
} else if ( count > 0 ) { //Normal work. Enable interrupt.
PDEBUG ( " Normal work. Enable interrupt. \n " ) ;
ctrl | = ME6000_AO_CTRL_BIT_ENABLE_IRQ ;
} else { //Normal work but there are no more data in buffer. Interrupt blocked. stream_write() will unblock it.
PDEBUG
( " No data in software buffer. Interrupt blocked. \n " ) ;
}
} else { //Error during copy.
instance - > status = ao_status_stream_fifo_error ;
}
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , ctrl ) ;
} else { //?? more than half
PDEBUG
( " Interrupt come but FIFO more than half full! Reset interrupt. \n " ) ;
}
PINFO ( " ISR: Buffer count: %d.(T:%d H:%d) \n " ,
me_circ_buf_values ( & instance - > circ_buf ) , instance - > circ_buf . tail ,
instance - > circ_buf . head ) ;
PINFO ( " ISR: Stop count: %d. \n " , instance - > stop_count ) ;
PINFO ( " ISR: Stop data count: %d. \n " , instance - > stop_data_count ) ;
PINFO ( " ISR: Data count: %d. \n " , instance - > data_count ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
//Inform user
wake_up_interruptible_all ( & instance - > wait_queue ) ;
return IRQ_HANDLED ;
}
static void me6000_ao_destructor ( struct me_subdevice * subdevice )
{
me6000_ao_subdevice_t * instance ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
instance - > ao_control_task_flag = 0 ;
// Reset subdevice to asure clean exit.
me6000_ao_io_reset_subdevice ( subdevice , NULL ,
ME_IO_RESET_SUBDEVICE_NO_FLAGS ) ;
// Remove any tasks from work queue. This is paranoic because it was done allready in reset().
if ( ! cancel_delayed_work ( & instance - > ao_control_task ) ) { //Wait 2 ticks to be sure that control task is removed from queue.
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_timeout ( 2 ) ;
}
if ( instance - > fifo & ME6000_AO_HAS_FIFO ) {
if ( instance - > irq ) {
free_irq ( instance - > irq , instance ) ;
instance - > irq = 0 ;
}
if ( instance - > circ_buf . buf ) {
PDEBUG ( " free circ_buf = %p size=%d " ,
instance - > circ_buf . buf ,
PAGE_SHIFT < < ME6000_AO_CIRC_BUF_SIZE_ORDER ) ;
free_pages ( ( unsigned long ) instance - > circ_buf . buf ,
ME6000_AO_CIRC_BUF_SIZE_ORDER ) ;
}
instance - > circ_buf . buf = NULL ;
}
me_subdevice_deinit ( & instance - > base ) ;
kfree ( instance ) ;
}
me6000_ao_subdevice_t * me6000_ao_constructor ( uint32_t reg_base ,
spinlock_t * preload_reg_lock ,
uint32_t * preload_flags ,
uint32_t * triggering_flags ,
int ao_idx ,
int fifo ,
int irq ,
int high_range ,
struct workqueue_struct * me6000_wq )
{
me6000_ao_subdevice_t * subdevice ;
int err ;
PDEBUG ( " executed ID=%d. \n " , ao_idx ) ;
/* Allocate memory for subdevice instance */
subdevice = kmalloc ( sizeof ( me6000_ao_subdevice_t ) , GFP_KERNEL ) ;
if ( ! subdevice ) {
PERROR ( " Cannot get memory for subdevice instance. \n " ) ;
return NULL ;
}
memset ( subdevice , 0 , sizeof ( me6000_ao_subdevice_t ) ) ;
/* Initialize subdevice base class */
err = me_subdevice_init ( & subdevice - > base ) ;
if ( err ) {
PERROR ( " Cannot initialize subdevice base class instance. \n " ) ;
kfree ( subdevice ) ;
return NULL ;
}
// Initialize spin locks.
spin_lock_init ( & subdevice - > subdevice_lock ) ;
subdevice - > preload_reg_lock = preload_reg_lock ;
subdevice - > preload_flags = preload_flags ;
subdevice - > triggering_flags = triggering_flags ;
/* Store analog output index */
subdevice - > ao_idx = ao_idx ;
/* Store if analog output has fifo */
subdevice - > fifo = fifo ;
if ( subdevice - > fifo & ME6000_AO_HAS_FIFO ) {
/* Allocate and initialize circular buffer */
subdevice - > circ_buf . mask = ME6000_AO_CIRC_BUF_COUNT - 1 ;
subdevice - > circ_buf . buf =
( void * ) __get_free_pages ( GFP_KERNEL ,
ME6000_AO_CIRC_BUF_SIZE_ORDER ) ;
PDEBUG ( " circ_buf = %p size=%ld \n " , subdevice - > circ_buf . buf ,
ME6000_AO_CIRC_BUF_SIZE ) ;
if ( ! subdevice - > circ_buf . buf ) {
PERROR
( " Cannot initialize subdevice base class instance. \n " ) ;
kfree ( subdevice ) ;
return NULL ;
}
memset ( subdevice - > circ_buf . buf , 0 , ME6000_AO_CIRC_BUF_SIZE ) ;
} else {
subdevice - > circ_buf . mask = 0 ;
subdevice - > circ_buf . buf = NULL ;
}
subdevice - > circ_buf . head = 0 ;
subdevice - > circ_buf . tail = 0 ;
subdevice - > status = ao_status_none ;
subdevice - > ao_control_task_flag = 0 ;
subdevice - > timeout . delay = 0 ;
subdevice - > timeout . start_time = jiffies ;
/* Initialize wait queue */
init_waitqueue_head ( & subdevice - > wait_queue ) ;
/* Initialize single value to 0V */
subdevice - > single_value = 0x8000 ;
subdevice - > single_value_in_fifo = 0x8000 ;
/* Initialize range boarders */
if ( high_range ) {
subdevice - > min = ME6000_AO_MIN_RANGE_HIGH ;
subdevice - > max = ME6000_AO_MAX_RANGE_HIGH ;
} else {
subdevice - > min = ME6000_AO_MIN_RANGE ;
subdevice - > max = ME6000_AO_MAX_RANGE ;
}
/* Register interrupt service routine */
if ( subdevice - > fifo & ME6000_AO_HAS_FIFO ) {
subdevice - > irq = irq ;
if ( request_irq ( subdevice - > irq , me6000_ao_isr ,
# ifdef IRQF_DISABLED
IRQF_DISABLED | IRQF_SHARED ,
# else
SA_INTERRUPT | SA_SHIRQ ,
# endif
ME6000_NAME , subdevice ) ) {
PERROR ( " Cannot get interrupt line. \n " ) ;
PDEBUG ( " free circ_buf = %p size=%d " ,
subdevice - > circ_buf . buf ,
PAGE_SHIFT < < ME6000_AO_CIRC_BUF_SIZE_ORDER ) ;
free_pages ( ( unsigned long ) subdevice - > circ_buf . buf ,
ME6000_AO_CIRC_BUF_SIZE_ORDER ) ;
subdevice - > circ_buf . buf = NULL ;
kfree ( subdevice ) ;
return NULL ;
}
PINFO ( " Registered irq=%d. \n " , subdevice - > irq ) ;
} else {
subdevice - > irq = 0 ;
}
/* Initialize registers */
// Only streamed subdevices support interrupts. For the rest this register has no meaning.
subdevice - > irq_status_reg = reg_base + ME6000_AO_IRQ_STATUS_REG ;
subdevice - > preload_reg = reg_base + ME6000_AO_PRELOAD_REG ;
if ( ao_idx = = 0 ) {
subdevice - > ctrl_reg = reg_base + ME6000_AO_00_CTRL_REG ;
subdevice - > status_reg = reg_base + ME6000_AO_00_STATUS_REG ;
subdevice - > fifo_reg = reg_base + ME6000_AO_00_FIFO_REG ;
subdevice - > timer_reg = reg_base + ME6000_AO_00_TIMER_REG ;
subdevice - > irq_reset_reg =
reg_base + ME6000_AO_00_IRQ_RESET_REG ;
subdevice - > single_reg = reg_base + ME6000_AO_00_SINGLE_REG ;
} else if ( ao_idx = = 1 ) {
subdevice - > ctrl_reg = reg_base + ME6000_AO_01_CTRL_REG ;
subdevice - > status_reg = reg_base + ME6000_AO_01_STATUS_REG ;
subdevice - > fifo_reg = reg_base + ME6000_AO_01_FIFO_REG ;
subdevice - > timer_reg = reg_base + ME6000_AO_01_TIMER_REG ;
subdevice - > irq_reset_reg =
reg_base + ME6000_AO_01_IRQ_RESET_REG ;
subdevice - > single_reg = reg_base + ME6000_AO_01_SINGLE_REG ;
} else if ( ao_idx = = 2 ) {
subdevice - > ctrl_reg = reg_base + ME6000_AO_02_CTRL_REG ;
subdevice - > status_reg = reg_base + ME6000_AO_02_STATUS_REG ;
subdevice - > fifo_reg = reg_base + ME6000_AO_02_FIFO_REG ;
subdevice - > timer_reg = reg_base + ME6000_AO_02_TIMER_REG ;
subdevice - > irq_reset_reg =
reg_base + ME6000_AO_02_IRQ_RESET_REG ;
subdevice - > single_reg = reg_base + ME6000_AO_02_SINGLE_REG ;
} else if ( ao_idx = = 3 ) {
subdevice - > ctrl_reg = reg_base + ME6000_AO_03_CTRL_REG ;
subdevice - > status_reg = reg_base + ME6000_AO_03_STATUS_REG ;
subdevice - > fifo_reg = reg_base + ME6000_AO_03_FIFO_REG ;
subdevice - > timer_reg = reg_base + ME6000_AO_03_TIMER_REG ;
subdevice - > irq_reset_reg =
reg_base + ME6000_AO_03_IRQ_RESET_REG ;
subdevice - > single_reg = reg_base + ME6000_AO_03_SINGLE_REG ;
} else {
subdevice - > ctrl_reg = reg_base + ME6000_AO_DUMY ;
subdevice - > fifo_reg = reg_base + ME6000_AO_DUMY ;
subdevice - > timer_reg = reg_base + ME6000_AO_DUMY ;
subdevice - > irq_reset_reg = reg_base + ME6000_AO_DUMY ;
subdevice - > single_reg = reg_base + ME6000_AO_DUMY ;
subdevice - > status_reg = reg_base + ME6000_AO_SINGLE_STATUS_REG ;
if ( ao_idx = = 4 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_04_SINGLE_REG ;
} else if ( ao_idx = = 5 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_05_SINGLE_REG ;
} else if ( ao_idx = = 6 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_06_SINGLE_REG ;
} else if ( ao_idx = = 7 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_07_SINGLE_REG ;
} else if ( ao_idx = = 8 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_08_SINGLE_REG ;
} else if ( ao_idx = = 9 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_09_SINGLE_REG ;
} else if ( ao_idx = = 10 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_10_SINGLE_REG ;
} else if ( ao_idx = = 11 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_11_SINGLE_REG ;
} else if ( ao_idx = = 12 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_12_SINGLE_REG ;
} else if ( ao_idx = = 13 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_13_SINGLE_REG ;
} else if ( ao_idx = = 14 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_14_SINGLE_REG ;
} else if ( ao_idx = = 15 ) {
subdevice - > single_reg =
reg_base + ME6000_AO_15_SINGLE_REG ;
} else {
PERROR_CRITICAL ( " WRONG SUBDEVICE ID=%d! " , ao_idx ) ;
me_subdevice_deinit ( ( me_subdevice_t * ) subdevice ) ;
if ( subdevice - > fifo ) {
free_pages ( ( unsigned long ) subdevice - > circ_buf .
buf , ME6000_AO_CIRC_BUF_SIZE_ORDER ) ;
}
subdevice - > circ_buf . buf = NULL ;
kfree ( subdevice ) ;
return NULL ;
}
}
# ifdef MEDEBUG_DEBUG_REG
subdevice - > reg_base = reg_base ;
# endif
/* Override base class methods. */
subdevice - > base . me_subdevice_destructor = me6000_ao_destructor ;
subdevice - > base . me_subdevice_io_reset_subdevice =
me6000_ao_io_reset_subdevice ;
subdevice - > base . me_subdevice_io_single_config =
me6000_ao_io_single_config ;
subdevice - > base . me_subdevice_io_single_read = me6000_ao_io_single_read ;
subdevice - > base . me_subdevice_io_single_write =
me6000_ao_io_single_write ;
subdevice - > base . me_subdevice_io_stream_config =
me6000_ao_io_stream_config ;
subdevice - > base . me_subdevice_io_stream_new_values =
me6000_ao_io_stream_new_values ;
subdevice - > base . me_subdevice_io_stream_write =
me6000_ao_io_stream_write ;
subdevice - > base . me_subdevice_io_stream_start =
me6000_ao_io_stream_start ;
subdevice - > base . me_subdevice_io_stream_status =
me6000_ao_io_stream_status ;
subdevice - > base . me_subdevice_io_stream_stop = me6000_ao_io_stream_stop ;
subdevice - > base . me_subdevice_query_number_channels =
me6000_ao_query_number_channels ;
subdevice - > base . me_subdevice_query_subdevice_type =
me6000_ao_query_subdevice_type ;
subdevice - > base . me_subdevice_query_subdevice_caps =
me6000_ao_query_subdevice_caps ;
subdevice - > base . me_subdevice_query_subdevice_caps_args =
me6000_ao_query_subdevice_caps_args ;
subdevice - > base . me_subdevice_query_range_by_min_max =
me6000_ao_query_range_by_min_max ;
subdevice - > base . me_subdevice_query_number_ranges =
me6000_ao_query_number_ranges ;
subdevice - > base . me_subdevice_query_range_info =
me6000_ao_query_range_info ;
subdevice - > base . me_subdevice_query_timer = me6000_ao_query_timer ;
//prepare work queue and work function
subdevice - > me6000_workqueue = me6000_wq ;
/* workqueue API changed in kernel 2.6.20 */
# if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) )
INIT_WORK ( & subdevice - > ao_control_task , me6000_ao_work_control_task ,
( void * ) subdevice ) ;
# else
INIT_DELAYED_WORK ( & subdevice - > ao_control_task ,
me6000_ao_work_control_task ) ;
# endif
if ( subdevice - > fifo ) { //Set speed
outl ( ME6000_AO_MIN_CHAN_TICKS - 1 , subdevice - > timer_reg ) ;
subdevice - > hardware_stop_delay = HZ / 10 ; //100ms
}
return subdevice ;
}
/** @brief Stop presentation. Preserve FIFOs.
*
* @ param instance The subdevice instance ( pointer ) .
*/
int inline ao_stop_immediately ( me6000_ao_subdevice_t * instance )
{
unsigned long cpu_flags ;
uint32_t ctrl ;
int timeout ;
int i ;
uint32_t single_mask ;
2009-01-18 14:34:55 +00:00
if ( instance - > ao_idx < ME6000_AO_SINGLE_STATUS_OFFSET )
single_mask = 0x0000 ;
else
single_mask = 0x0001 < < ( instance - > ao_idx -
ME6000_AO_SINGLE_STATUS_OFFSET ) ;
2008-10-31 23:39:12 +00:00
timeout =
( instance - > hardware_stop_delay >
( HZ / 10 ) ) ? instance - > hardware_stop_delay : HZ / 10 ;
for ( i = 0 ; i < = timeout ; i + + ) {
if ( instance - > fifo ) {
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
// Stop all actions. No conditions! Block interrupts. Leave FIFO untouched!
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | =
ME6000_AO_CTRL_BIT_STOP |
ME6000_AO_CTRL_BIT_IMMEDIATE_STOP ;
ctrl & =
~ ( ME6000_AO_CTRL_BIT_ENABLE_IRQ |
ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ) ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
ctrl ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
if ( ! ( inl ( instance - > status_reg ) & ME6000_AO_STATUS_BIT_FSM ) ) { // Exit.
break ;
}
} else {
if ( ! ( inl ( instance - > status_reg ) & single_mask ) ) { // Exit.
break ;
}
}
2009-01-07 22:31:57 +00:00
PINFO ( " <%s> Wait for stop: %d \n " , __func__ , i ) ;
2008-10-31 23:39:12 +00:00
//Still working!
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_timeout ( 1 ) ;
}
if ( i > timeout ) {
PERROR_CRITICAL ( " FSM IS BUSY! \n " ) ;
return ME_ERRNO_INTERNAL ;
}
return ME_ERRNO_SUCCESS ;
}
/** @brief Copy data from circular buffer to fifo (fast) in wraparound.
* @ note This is time critical function . Checking is done at begining and end only .
* @ note The is not reasonable way to check how many walues was in FIFO at begining . The count must be managed externaly .
*
* @ param instance The subdevice instance ( pointer ) .
* @ param count Maximum number of copied data .
* @ param start_pos Position of the firs value in buffer .
*
* @ return On success : Number of copied data .
* @ return On error / success : 0. No datas were copied = > no data in buffer .
* @ return On error : - ME_ERRNO_FIFO_BUFFER_OVERFLOW .
*/
int inline ao_write_data_wraparound ( me6000_ao_subdevice_t * instance , int count ,
int start_pos )
{ /// @note This is time critical function!
uint32_t status ;
uint32_t value ;
int pos =
( instance - > circ_buf . tail + start_pos ) & instance - > circ_buf . mask ;
int local_count = count ;
int i = 1 ;
if ( count < = 0 ) { //Wrong count!
return 0 ;
}
while ( i < local_count ) {
//Get value from buffer
value = * ( instance - > circ_buf . buf + pos ) ;
//Prepare it
if ( instance - > ao_idx & 0x1 ) {
value < < = 16 ;
}
//Put value to FIFO
outl ( value , instance - > fifo_reg ) ;
//PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value);
pos + + ;
pos & = instance - > circ_buf . mask ;
if ( pos = = instance - > circ_buf . head ) {
pos = instance - > circ_buf . tail ;
}
i + + ;
}
status = inl ( instance - > status_reg ) ;
if ( ! ( status & ME6000_AO_STATUS_BIT_FF ) ) { //FIFO is full before all datas were copied!
PERROR ( " idx=%d FIFO is full before all datas were copied! \n " ,
instance - > ao_idx ) ;
return - ME_ERRNO_FIFO_BUFFER_OVERFLOW ;
} else { //Add last value
value = * ( instance - > circ_buf . buf + pos ) ;
if ( instance - > ao_idx & 0x1 ) {
value < < = 16 ;
}
//Put value to FIFO
outl ( value , instance - > fifo_reg ) ;
//PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value);
}
PINFO ( " idx=%d WRAPAROUND LOADED %d values \n " , instance - > ao_idx ,
local_count ) ;
return local_count ;
}
/** @brief Copy data from software buffer to fifo (fast).
* @ note This is time critical function . Checking is done at begining and end only .
* @ note The is not reasonable way to check how many walues was in FIFO at begining . The count must be managed externaly .
*
* @ param instance The subdevice instance ( pointer ) .
* @ param count Maximum number of copied data .
* @ param start_pos Position of the firs value in buffer .
*
* @ return On success : Number of copied data .
* @ return On error / success : 0. No datas were copied = > no data in buffer .
* @ return On error : - ME_ERRNO_FIFO_BUFFER_OVERFLOW .
*/
int inline ao_write_data ( me6000_ao_subdevice_t * instance , int count ,
int start_pos )
{ /// @note This is time critical function!
uint32_t status ;
uint32_t value ;
int pos =
( instance - > circ_buf . tail + start_pos ) & instance - > circ_buf . mask ;
int local_count = count ;
int max_count ;
int i = 1 ;
if ( count < = 0 ) { //Wrong count!
return 0 ;
}
max_count = me_circ_buf_values ( & instance - > circ_buf ) - start_pos ;
if ( max_count < = 0 ) { //No data to copy!
return 0 ;
}
if ( max_count < count ) {
local_count = max_count ;
}
while ( i < local_count ) {
//Get value from buffer
value = * ( instance - > circ_buf . buf + pos ) ;
//Prepare it
if ( instance - > ao_idx & 0x1 ) {
value < < = 16 ;
}
//Put value to FIFO
outl ( value , instance - > fifo_reg ) ;
//PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value);
pos + + ;
pos & = instance - > circ_buf . mask ;
i + + ;
}
status = inl ( instance - > status_reg ) ;
if ( ! ( status & ME6000_AO_STATUS_BIT_FF ) ) { //FIFO is full before all datas were copied!
PERROR ( " idx=%d FIFO is full before all datas were copied! \n " ,
instance - > ao_idx ) ;
return - ME_ERRNO_FIFO_BUFFER_OVERFLOW ;
} else { //Add last value
value = * ( instance - > circ_buf . buf + pos ) ;
if ( instance - > ao_idx & 0x1 ) {
value < < = 16 ;
}
//Put value to FIFO
outl ( value , instance - > fifo_reg ) ;
//PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value);
}
PINFO ( " idx=%d FAST LOADED %d values \n " , instance - > ao_idx , local_count ) ;
return local_count ;
}
/** @brief Copy data from software buffer to fifo (slow).
* @ note This is slow function that copy all data from buffer to FIFO with full control .
*
* @ param instance The subdevice instance ( pointer ) .
* @ param count Maximum number of copied data .
* @ param start_pos Position of the firs value in buffer .
*
* @ return On success : Number of copied values .
* @ return On error / success : 0. FIFO was full at begining .
* @ return On error : - ME_ERRNO_RING_BUFFER_UNDEFFLOW .
*/
int inline ao_write_data_pooling ( me6000_ao_subdevice_t * instance , int count ,
int start_pos )
{ /// @note This is slow function!
uint32_t status ;
uint32_t value ;
int pos =
( instance - > circ_buf . tail + start_pos ) & instance - > circ_buf . mask ;
int local_count = count ;
int i ;
int max_count ;
if ( count < = 0 ) { //Wrong count!
PERROR ( " idx=%d SLOW LOADED: Wrong count! \n " , instance - > ao_idx ) ;
return 0 ;
}
max_count = me_circ_buf_values ( & instance - > circ_buf ) - start_pos ;
if ( max_count < = 0 ) { //No data to copy!
PERROR ( " idx=%d SLOW LOADED: No data to copy! \n " ,
instance - > ao_idx ) ;
return 0 ;
}
if ( max_count < count ) {
local_count = max_count ;
}
for ( i = 0 ; i < local_count ; i + + ) {
status = inl ( instance - > status_reg ) ;
if ( ! ( status & ME6000_AO_STATUS_BIT_FF ) ) { //FIFO is full!
return i ;
}
//Get value from buffer
value = * ( instance - > circ_buf . buf + pos ) ;
//Prepare it
if ( instance - > ao_idx & 0x1 ) {
value < < = 16 ;
}
//Put value to FIFO
outl ( value , instance - > fifo_reg ) ;
//PDEBUG_REG("idx=%d fifo_reg outl(0x%lX+0x%lX)=0x%x\n", instance->ao_idx, instance->reg_base, instance->fifo_reg - instance->reg_base, value);
pos + + ;
pos & = instance - > circ_buf . mask ;
}
PINFO ( " idx=%d SLOW LOADED %d values \n " , instance - > ao_idx , local_count ) ;
return local_count ;
}
/** @brief Copy data from user space to circular buffer.
* @ param instance The subdevice instance ( pointer ) .
* @ param count Number of datas in user space .
* @ param user_values Buffer ' s pointer .
*
* @ return On success : Number of copied values .
* @ return On error : - ME_ERRNO_INTERNAL .
*/
int inline ao_get_data_from_user ( me6000_ao_subdevice_t * instance , int count ,
int * user_values )
{
int i , err ;
int empty_space ;
int copied ;
int value ;
empty_space = me_circ_buf_space ( & instance - > circ_buf ) ;
//We have only this space free.
copied = ( count < empty_space ) ? count : empty_space ;
for ( i = 0 ; i < copied ; i + + ) { //Copy from user to buffer
if ( ( err = get_user ( value , ( int * ) ( user_values + i ) ) ) ) {
PERROR
( " idx=%d BUFFER LOADED: get_user(0x%p) return an error: %d \n " ,
instance - > ao_idx , user_values + i , err ) ;
return - ME_ERRNO_INTERNAL ;
}
/// @note The analog output in me6000 series has size of 16 bits.
* ( instance - > circ_buf . buf + instance - > circ_buf . head ) =
( uint16_t ) value ;
instance - > circ_buf . head + + ;
instance - > circ_buf . head & = instance - > circ_buf . mask ;
}
PINFO ( " idx=%d BUFFER LOADED %d values \n " , instance - > ao_idx , copied ) ;
return copied ;
}
static void me6000_ao_work_control_task (
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
void * subdevice
# else
struct work_struct * work
# endif
)
{
me6000_ao_subdevice_t * instance ;
unsigned long cpu_flags = 0 ;
uint32_t status ;
uint32_t ctrl ;
uint32_t synch ;
int reschedule = 0 ;
int signaling = 0 ;
uint32_t single_mask ;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
instance = ( me6000_ao_subdevice_t * ) subdevice ;
# else
instance =
container_of ( ( void * ) work , me6000_ao_subdevice_t , ao_control_task ) ;
# endif
2009-01-07 22:31:57 +00:00
PINFO ( " <%s: %ld> executed. idx=%d \n " , __func__ , jiffies ,
2008-10-31 23:39:12 +00:00
instance - > ao_idx ) ;
status = inl ( instance - > status_reg ) ;
PDEBUG_REG ( " status_reg inl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > status_reg - instance - > reg_base , status ) ;
/// @note AO_STATUS_BIT_FSM doesn't work as should be for pure single channels (idx>=4)
// single_mask = (instance->ao_idx-ME6000_AO_SINGLE_STATUS_OFFSET < 0) ? 0x0000 : (0x0001 << (instance->ao_idx-ME6000_AO_SINGLE_STATUS_OFFSET));
single_mask = * instance - > triggering_flags & ( 0x1 < < instance - > ao_idx ) ;
switch ( instance - > status ) { // Checking actual mode.
// Not configured for work.
case ao_status_none :
break ;
//This are stable modes. No need to do anything. (?)
case ao_status_single_configured :
case ao_status_stream_configured :
case ao_status_stream_fifo_error :
case ao_status_stream_buffer_error :
case ao_status_stream_error :
PERROR ( " Shouldn't be running!. \n " ) ;
break ;
// Single modes
case ao_status_single_run_wait :
case ao_status_single_run :
case ao_status_single_end_wait :
if ( instance - > fifo ) { // Extra registers.
if ( ! ( status & ME6000_AO_STATUS_BIT_FSM ) ) { // State machine is not working.
if ( ( ( instance - > fifo & ME6000_AO_HAS_FIFO )
& & ( ! ( status & ME6000_AO_STATUS_BIT_EF ) ) )
| | ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) ) { // Single is in end state.
PDEBUG
( " Single call has been complited. \n " ) ;
// Set correct value for single_read();
instance - > single_value =
instance - > single_value_in_fifo ;
// Set status as 'ao_status_single_end'
instance - > status = ao_status_single_end ;
spin_lock ( instance - > preload_reg_lock ) ;
if ( ( single_mask ) & & ( * instance - > preload_flags & ( ME6000_AO_SYNC_HOLD < < instance - > ao_idx ) ) ) { // This is one of synchronous start channels. Set all as triggered.
* instance - > triggering_flags =
0x00000000 ;
} else {
//Set this channel as triggered (none active).
* instance - > triggering_flags & =
~ ( 0x1 < < instance - > ao_idx ) ;
}
spin_unlock ( instance - > preload_reg_lock ) ;
// Signal the end.
signaling = 1 ;
// Wait for stop ISM.
reschedule = 1 ;
break ;
}
}
// Check timeout.
if ( ( instance - > timeout . delay ) & & ( ( jiffies - instance - > timeout . start_time ) > = instance - > timeout . delay ) ) { // Timeout
PDEBUG ( " Timeout reached. \n " ) ;
// Stop all actions. No conditions! Block interrupts and trigger. Leave FIFO untouched!
spin_lock_irqsave ( & instance - > subdevice_lock ,
cpu_flags ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | =
ME6000_AO_CTRL_BIT_STOP |
ME6000_AO_CTRL_BIT_IMMEDIATE_STOP ;
ctrl & =
~ ( ME6000_AO_CTRL_BIT_ENABLE_IRQ |
ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ) ;
ctrl & =
~ ( ME6000_AO_CTRL_BIT_EX_TRIG_EDGE |
ME6000_AO_CTRL_BIT_EX_TRIG_EDGE_BOTH ) ;
//Disabling FIFO
ctrl & = ~ ME6000_AO_CTRL_BIT_ENABLE_FIFO ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg -
instance - > reg_base , ctrl ) ;
spin_unlock_irqrestore ( & instance - >
subdevice_lock ,
cpu_flags ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
spin_lock ( instance - > preload_reg_lock ) ;
//Remove from synchronous start. Block triggering from this output.
synch = inl ( instance - > preload_reg ) ;
synch & =
~ ( ( ME6000_AO_SYNC_HOLD |
ME6000_AO_SYNC_EXT_TRIG ) < < instance - >
ao_idx ) ;
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) { // No FIFO - set to single safe mode
synch | =
ME6000_AO_SYNC_HOLD < < instance - >
ao_idx ;
}
outl ( synch , instance - > preload_reg ) ;
PDEBUG_REG
( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
synch ) ;
//Set this channel as triggered (none active).
* instance - > triggering_flags & =
~ ( 0x1 < < instance - > ao_idx ) ;
spin_unlock ( instance - > preload_reg_lock ) ;
// Set correct value for single_read();
instance - > single_value_in_fifo =
instance - > single_value ;
instance - > status = ao_status_single_end ;
// Signal the end.
signaling = 1 ;
}
} else { // No extra registers.
/*
if ( ! ( status & single_mask ) )
{ // State machine is not working.
PDEBUG ( " Single call has been complited. \n " ) ;
// Set correct value for single_read();
instance - > single_value = instance - > single_value_in_fifo ;
// Set status as 'ao_status_single_end'
instance - > status = ao_status_single_end ;
// Signal the end.
signaling = 1 ;
// Wait for stop ISM.
reschedule = 1 ;
break ;
}
*/
if ( ! single_mask ) { // Was triggered.
PDEBUG ( " Single call has been complited. \n " ) ;
// Set correct value for single_read();
instance - > single_value =
instance - > single_value_in_fifo ;
// Set status as 'ao_status_single_end'
instance - > status = ao_status_single_end ;
// Signal the end.
signaling = 1 ;
break ;
}
// Check timeout.
if ( ( instance - > timeout . delay ) & & ( ( jiffies - instance - > timeout . start_time ) > = instance - > timeout . delay ) ) { // Timeout
PDEBUG ( " Timeout reached. \n " ) ;
spin_lock ( instance - > preload_reg_lock ) ;
//Remove from synchronous start. Block triggering from this output.
synch = inl ( instance - > preload_reg ) ;
synch & =
~ ( ME6000_AO_SYNC_EXT_TRIG < < instance - >
ao_idx ) ;
synch | =
ME6000_AO_SYNC_HOLD < < instance - > ao_idx ;
outl ( synch , instance - > preload_reg ) ;
PDEBUG_REG
( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
synch ) ;
//Set this channel as triggered (none active).
* instance - > triggering_flags & =
~ ( 0x1 < < instance - > ao_idx ) ;
spin_unlock ( instance - > preload_reg_lock ) ;
// Restore old settings.
PDEBUG ( " Write old value back to register. \n " ) ;
outl ( instance - > single_value ,
instance - > single_reg ) ;
PDEBUG_REG
( " single_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > single_reg - instance - > reg_base ,
instance - > single_value ) ;
// Set correct value for single_read();
instance - > single_value_in_fifo =
instance - > single_value ;
instance - > status = ao_status_single_end ;
// Signal the end.
signaling = 1 ;
}
}
// Wait for stop.
reschedule = 1 ;
break ;
case ao_status_stream_end :
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) { // No FIFO
PERROR_CRITICAL
( " Streaming on single device! This feature is not implemented in this version! \n " ) ;
instance - > status = ao_status_stream_error ;
// Signal the end.
signaling = 1 ;
break ;
}
case ao_status_single_end :
if ( instance - > fifo ) { // Extra registers.
if ( status & ME6000_AO_STATUS_BIT_FSM ) { // State machine is working but the status is set to end. Force stop.
// Wait for stop.
reschedule = 1 ;
}
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
// Stop all actions. No conditions! Block interrupts and trigger. Leave FIFO untouched!
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | =
ME6000_AO_CTRL_BIT_IMMEDIATE_STOP |
ME6000_AO_CTRL_BIT_STOP ;
ctrl & =
~ ( ME6000_AO_CTRL_BIT_ENABLE_IRQ |
ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ) ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
ctrl ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
} else { // No extra registers.
/*
if ( status & single_mask )
{ // State machine is working but the status is set to end. Force stop.
// Wait for stop.
reschedule = 1 ;
}
*/
}
break ;
// Stream modes
case ao_status_stream_run_wait :
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) { // No FIFO
PERROR_CRITICAL
( " Streaming on single device! This feature is not implemented in this version! \n " ) ;
instance - > status = ao_status_stream_error ;
// Signal the end.
signaling = 1 ;
break ;
}
if ( status & ME6000_AO_STATUS_BIT_FSM ) { // State machine is working. Waiting for start finish.
instance - > status = ao_status_stream_run ;
// Signal end of this step
signaling = 1 ;
} else { // State machine is not working.
if ( ! ( status & ME6000_AO_STATUS_BIT_EF ) ) { // FIFO is empty. Procedure has started and finish already!
instance - > status = ao_status_stream_end ;
// Signal the end.
signaling = 1 ;
// Wait for stop.
reschedule = 1 ;
break ;
}
}
// Check timeout.
if ( ( instance - > timeout . delay ) & & ( ( jiffies - instance - > timeout . start_time ) > = instance - > timeout . delay ) ) { // Timeout
PDEBUG ( " Timeout reached. \n " ) ;
// Stop all actions. No conditions! Block interrupts. Leave FIFO untouched!
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | =
ME6000_AO_CTRL_BIT_STOP |
ME6000_AO_CTRL_BIT_IMMEDIATE_STOP ;
ctrl & =
~ ( ME6000_AO_CTRL_BIT_ENABLE_IRQ |
ME6000_AO_CTRL_BIT_ENABLE_EX_TRIG ) ;
outl ( ctrl , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
ctrl ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock ,
cpu_flags ) ;
//Reset interrupt latch
inl ( instance - > irq_reset_reg ) ;
spin_lock ( instance - > preload_reg_lock ) ;
//Remove from synchronous start. Block triggering from this output.
synch = inl ( instance - > preload_reg ) ;
synch & =
~ ( ( ME6000_AO_SYNC_HOLD | ME6000_AO_SYNC_EXT_TRIG ) < <
instance - > ao_idx ) ;
outl ( synch , instance - > preload_reg ) ;
PDEBUG_REG ( " preload_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > preload_reg - instance - > reg_base ,
synch ) ;
spin_unlock ( instance - > preload_reg_lock ) ;
instance - > status = ao_status_stream_end ;
// Signal the end.
signaling = 1 ;
}
// Wait for stop.
reschedule = 1 ;
break ;
case ao_status_stream_run :
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) { // No FIFO
PERROR_CRITICAL
( " Streaming on single device! This feature is not implemented in this version! \n " ) ;
instance - > status = ao_status_stream_error ;
// Signal the end.
signaling = 1 ;
break ;
}
if ( ! ( status & ME6000_AO_STATUS_BIT_FSM ) ) { // State machine is not working. This is an error.
// BROKEN PIPE!
if ( ! ( status & ME6000_AO_STATUS_BIT_EF ) ) { // FIFO is empty.
if ( me_circ_buf_values ( & instance - > circ_buf ) ) { // Software buffer is not empty.
if ( instance - > stop_data_count & & ( instance - > stop_data_count < = instance - > data_count ) ) { //Finishing work. Requed data shown.
PDEBUG
( " ISM stoped. No data in FIFO. Buffer is not empty. \n " ) ;
instance - > status =
ao_status_stream_end ;
} else {
PERROR
( " Output stream has been broken. ISM stoped. No data in FIFO. Buffer is not empty. \n " ) ;
instance - > status =
ao_status_stream_buffer_error ;
}
} else { // Software buffer is empty.
PDEBUG
( " ISM stoped. No data in FIFO. Buffer is empty. \n " ) ;
instance - > status = ao_status_stream_end ;
}
} else { // There are still datas in FIFO.
if ( me_circ_buf_values ( & instance - > circ_buf ) ) { // Software buffer is not empty.
PERROR
( " Output stream has been broken. ISM stoped but some data in FIFO and buffer. \n " ) ;
} else { // Software buffer is empty.
PERROR
( " Output stream has been broken. ISM stoped but some data in FIFO. Buffer is empty. \n " ) ;
}
instance - > status = ao_status_stream_fifo_error ;
}
// Signal the failure.
signaling = 1 ;
break ;
}
// Wait for stop.
reschedule = 1 ;
break ;
case ao_status_stream_end_wait :
if ( ! ( instance - > fifo & ME6000_AO_HAS_FIFO ) ) { // No FIFO
PERROR_CRITICAL
( " Streaming on single device! This feature is not implemented in this version! \n " ) ;
instance - > status = ao_status_stream_error ;
// Signal the end.
signaling = 1 ;
break ;
}
if ( ! ( status & ME6000_AO_STATUS_BIT_FSM ) ) { // State machine is not working. Waiting for stop finish.
instance - > status = ao_status_stream_end ;
signaling = 1 ;
}
// State machine is working.
reschedule = 1 ;
break ;
default :
PERROR_CRITICAL ( " Status is in wrong state (%d)! \n " ,
instance - > status ) ;
instance - > status = ao_status_stream_error ;
// Signal the end.
signaling = 1 ;
break ;
}
if ( signaling ) { //Signal it.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
}
if ( instance - > ao_control_task_flag & & reschedule ) { // Reschedule task
queue_delayed_work ( instance - > me6000_workqueue ,
& instance - > ao_control_task , 1 ) ;
} else {
2009-01-07 22:31:57 +00:00
PINFO ( " <%s> Ending control task. \n " , __func__ ) ;
2008-10-31 23:39:12 +00:00
}
}
static int me6000_ao_query_range_by_min_max ( me_subdevice_t * subdevice ,
int unit ,
int * min ,
int * max , int * maxdata , int * range )
{
me6000_ao_subdevice_t * instance ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( ( * max - * min ) < 0 ) {
PERROR ( " Invalid minimum and maximum values specified. \n " ) ;
return ME_ERRNO_INVALID_MIN_MAX ;
}
if ( ( unit = = ME_UNIT_VOLT ) | | ( unit = = ME_UNIT_ANY ) ) {
if ( ( * max < = ( instance - > max + 1000 ) ) & & ( * min > = instance - > min ) ) {
* min = instance - > min ;
* max = instance - > max ;
* maxdata = ME6000_AO_MAX_DATA ;
* range = 0 ;
} else {
PERROR ( " No matching range available. \n " ) ;
return ME_ERRNO_NO_RANGE ;
}
} else {
PERROR ( " Invalid physical unit specified. \n " ) ;
return ME_ERRNO_INVALID_UNIT ;
}
return ME_ERRNO_SUCCESS ;
}
static int me6000_ao_query_number_ranges ( me_subdevice_t * subdevice ,
int unit , int * count )
{
me6000_ao_subdevice_t * instance ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( ( unit = = ME_UNIT_VOLT ) | | ( unit = = ME_UNIT_ANY ) ) {
* count = 1 ;
} else {
* count = 0 ;
}
return ME_ERRNO_SUCCESS ;
}
static int me6000_ao_query_range_info ( me_subdevice_t * subdevice ,
int range ,
int * unit ,
int * min , int * max , int * maxdata )
{
me6000_ao_subdevice_t * instance ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( range = = 0 ) {
* unit = ME_UNIT_VOLT ;
* min = instance - > min ;
* max = instance - > max ;
* maxdata = ME6000_AO_MAX_DATA ;
} else {
PERROR ( " Invalid range number specified. \n " ) ;
return ME_ERRNO_INVALID_RANGE ;
}
return ME_ERRNO_SUCCESS ;
}
static int me6000_ao_query_timer ( me_subdevice_t * subdevice ,
int timer ,
int * base_frequency ,
long long * min_ticks , long long * max_ticks )
{
me6000_ao_subdevice_t * instance ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( instance - > fifo ) { //Streaming device.
* base_frequency = ME6000_AO_BASE_FREQUENCY ;
if ( timer = = ME_TIMER_ACQ_START ) {
* min_ticks = ME6000_AO_MIN_ACQ_TICKS ;
* max_ticks = ME6000_AO_MAX_ACQ_TICKS ;
} else if ( timer = = ME_TIMER_CONV_START ) {
* min_ticks = ME6000_AO_MIN_CHAN_TICKS ;
* max_ticks = ME6000_AO_MAX_CHAN_TICKS ;
}
} else { //Not streaming device!
* base_frequency = 0 ;
* min_ticks = 0 ;
* max_ticks = 0 ;
}
return ME_ERRNO_SUCCESS ;
}
static int me6000_ao_query_number_channels ( me_subdevice_t * subdevice ,
int * number )
{
me6000_ao_subdevice_t * instance ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
* number = 1 ;
return ME_ERRNO_SUCCESS ;
}
static int me6000_ao_query_subdevice_type ( me_subdevice_t * subdevice ,
int * type , int * subtype )
{
me6000_ao_subdevice_t * instance ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
* type = ME_TYPE_AO ;
* subtype =
( instance - >
fifo & ME6000_AO_HAS_FIFO ) ? ME_SUBTYPE_STREAMING :
ME_SUBTYPE_SINGLE ;
return ME_ERRNO_SUCCESS ;
}
static int me6000_ao_query_subdevice_caps ( me_subdevice_t * subdevice , int * caps )
{
me6000_ao_subdevice_t * instance ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
* caps =
ME_CAPS_AO_TRIG_SYNCHRONOUS | ( ( instance - > fifo ) ? ME_CAPS_AO_FIFO :
ME_CAPS_NONE ) ;
return ME_ERRNO_SUCCESS ;
}
static int me6000_ao_query_subdevice_caps_args ( struct me_subdevice * subdevice ,
int cap , int * args , int count )
{
me6000_ao_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
instance = ( me6000_ao_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=%d \n " , instance - > ao_idx ) ;
if ( count ! = 1 ) {
PERROR ( " Invalid capability argument count. \n " ) ;
return ME_ERRNO_INVALID_CAP_ARG_COUNT ;
}
switch ( cap ) {
case ME_CAP_AI_FIFO_SIZE :
args [ 0 ] = ( instance - > fifo ) ? ME6000_AO_FIFO_COUNT : 0 ;
break ;
case ME_CAP_AI_BUFFER_SIZE :
args [ 0 ] =
( instance - > circ_buf . buf ) ? ME6000_AO_CIRC_BUF_COUNT : 0 ;
break ;
default :
PERROR ( " Invalid capability. \n " ) ;
err = ME_ERRNO_INVALID_CAP ;
args [ 0 ] = 0 ;
}
return err ;
}