2008-11-01 00:39:12 +01:00
/**
* @ file me4600_ai . c
*
* @ brief ME - 4000 analog input 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/module.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
2009-03-16 17:45:13 +01:00
# include <linux/io.h>
# include <linux/uaccess.h>
2008-11-01 00:39:12 +01:00
# include <linux/types.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include "medefines.h"
# include "meinternal.h"
# include "meerror.h"
# include "medebug.h"
# include "meids.h"
# include "me4600_reg.h"
# include "me4600_ai_reg.h"
# include "me4600_ai.h"
/*
* Declarations ( local )
*/
static void me4600_ai_destructor ( struct me_subdevice * subdevice ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_reset_subdevice ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep , int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_single_config ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int channel ,
int single_config ,
int ref ,
int trig_chan ,
int trig_type , int trig_edge , int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_single_read ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int channel ,
int * value , int time_out , int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_config ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
2009-03-16 17:45:13 +01:00
meIOStreamConfig_t * config_list ,
2008-11-01 00:39:12 +01:00
int count ,
2009-03-16 17:45:13 +01:00
meIOStreamTrigger_t * trigger ,
2008-11-01 00:39:12 +01:00
int fifo_irq_threshold , int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_read ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int read_mode ,
int * values , int * count , int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_new_values ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int time_out , int * count , int flags ) ;
2009-03-16 17:45:13 +01:00
static inline int me4600_ai_io_stream_read_get_value ( me4600_ai_subdevice_t *
2008-11-01 00:39:12 +01:00
instance , int * values ,
const int count ,
const int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_start ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int start_mode , int time_out , int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_stop ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int stop_mode , int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_status ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int wait ,
int * status , int * values , int flags ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_range_by_min_max ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int unit ,
int * min ,
int * max , int * maxdata , int * range ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_number_ranges ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int unit , int * count ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_range_info ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int range ,
int * unit ,
int * min , int * max , int * maxdata ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_timer ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int timer ,
int * base_frequency ,
long long * min_ticks , long long * max_ticks ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_number_channels ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int * number ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_subdevice_type ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int * type , int * subtype ) ;
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_subdevice_caps ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int * caps ) ;
static int me4600_ai_query_subdevice_caps_args ( struct me_subdevice * subdevice ,
int cap , int * args , int count ) ;
static irqreturn_t me4600_ai_isr ( int irq , void * dev_id ) ;
2009-03-16 17:45:13 +01:00
static int ai_mux_toggler ( me4600_ai_subdevice_t * subdevice ) ;
2008-11-01 00:39:12 +01:00
/** Immidiate stop.
* Reset all IRQ ' s sources . ( block laches )
* Preserve FIFO
*/
2009-03-16 17:45:13 +01:00
static int ai_stop_immediately ( me4600_ai_subdevice_t * instance ) ;
2008-11-01 00:39:12 +01:00
/** Immidiate stop.
* Reset all IRQ ' s sources . ( block laches )
* Reset data FIFO
*/
2009-03-16 17:45:13 +01:00
inline void ai_stop_isr ( me4600_ai_subdevice_t * instance ) ;
2008-11-01 00:39:12 +01:00
/** Interrupt logics.
* Read datas
* Reset latches
*/
2009-03-16 17:45:13 +01:00
void ai_limited_isr ( me4600_ai_subdevice_t * instance , const uint32_t irq_status ,
2008-11-01 00:39:12 +01:00
const uint32_t ctrl_status ) ;
2009-03-16 17:45:13 +01:00
void ai_infinite_isr ( me4600_ai_subdevice_t * instance ,
2008-11-01 00:39:12 +01:00
const uint32_t irq_status , const uint32_t ctrl_status ) ;
/** Last chunck of datas. We must reschedule sample counter.
* Leaving SC_RELOAD doesn ' t do any harm , but in some bad case can make extra interrupts .
* When threshold is wrongly set some IRQ are lost . ( ! ! ! )
*/
2009-03-16 17:45:13 +01:00
inline void ai_reschedule_SC ( me4600_ai_subdevice_t * instance ) ;
2008-11-01 00:39:12 +01:00
/** Read datas from FIFO and copy them to buffer */
2009-03-16 17:45:13 +01:00
static inline int ai_read_data ( me4600_ai_subdevice_t * instance ,
2008-11-01 00:39:12 +01:00
const int count ) ;
/** Copy rest of data from fifo to circular buffer.*/
2009-03-16 17:45:13 +01:00
static inline int ai_read_data_pooling ( me4600_ai_subdevice_t * instance ) ;
2008-11-01 00:39:12 +01:00
/** Set ISM to next state for infinite data aqusation mode*/
2009-03-16 17:45:13 +01:00
inline void ai_infinite_ISM ( me4600_ai_subdevice_t * instance ) ;
2008-11-01 00:39:12 +01:00
/** Set ISM to next state for define amount of data aqusation mode*/
2009-03-16 17:45:13 +01:00
inline void ai_limited_ISM ( me4600_ai_subdevice_t * instance ,
2008-11-01 00:39:12 +01:00
uint32_t irq_status ) ;
/** Set ISM to next stage for limited mode */
2009-03-16 17:45:13 +01:00
inline void ai_data_acquisition_logic ( me4600_ai_subdevice_t * instance ) ;
2008-11-01 00:39:12 +01:00
static void me4600_ai_work_control_task ( struct work_struct * work ) ;
/* Definitions
*/
me4600_ai_subdevice_t * me4600_ai_constructor ( uint32_t reg_base ,
unsigned int channels ,
unsigned int ranges ,
int isolated ,
int sh ,
int irq ,
2009-03-16 17:45:13 +01:00
spinlock_t * ctrl_reg_lock ,
2008-11-01 00:39:12 +01:00
struct workqueue_struct * me4600_wq )
{
me4600_ai_subdevice_t * subdevice ;
int err ;
unsigned int i ;
PDEBUG ( " executed. idx=0 \n " ) ;
// Allocate memory for subdevice instance.
subdevice = kmalloc ( sizeof ( me4600_ai_subdevice_t ) , GFP_KERNEL ) ;
if ( ! subdevice ) {
PERROR ( " Cannot get memory for subdevice instance. \n " ) ;
return NULL ;
}
memset ( subdevice , 0 , sizeof ( me4600_ai_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 - > ctrl_reg_lock = ctrl_reg_lock ;
// Initialize circular buffer.
subdevice - > circ_buf . mask = ME4600_AI_CIRC_BUF_COUNT - 1 ;
subdevice - > circ_buf . buf =
( void * ) __get_free_pages ( GFP_KERNEL , ME4600_AI_CIRC_BUF_SIZE_ORDER ) ;
PDEBUG ( " circ_buf = %p size=%ld \n " , subdevice - > circ_buf . buf ,
ME4600_AI_CIRC_BUF_SIZE ) ;
if ( ! subdevice - > circ_buf . buf ) {
PERROR ( " Cannot get circular buffer. \n " ) ;
me_subdevice_deinit ( ( me_subdevice_t * ) subdevice ) ;
kfree ( subdevice ) ;
return NULL ;
}
memset ( subdevice - > circ_buf . buf , 0 , ME4600_AI_CIRC_BUF_SIZE ) ;
subdevice - > circ_buf . head = 0 ;
subdevice - > circ_buf . tail = 0 ;
subdevice - > status = ai_status_none ;
// Initialize wait queue.
init_waitqueue_head ( & subdevice - > wait_queue ) ;
// Save the number of channels.
subdevice - > channels = channels ;
/* Initialize the single config entries to reset values */
for ( i = 0 ; i < channels ; i + + ) {
subdevice - > single_config [ i ] . status = ME_SINGLE_CHANNEL_NOT_CONFIGURED ; //not configured
}
// Save if isolated device.
subdevice - > isolated = isolated ;
// Save if sample and hold is available.
subdevice - > sh = sh ;
// Set stream config to not configured state.
subdevice - > fifo_irq_threshold = 0 ;
subdevice - > data_required = 0 ;
subdevice - > chan_list_len = 0 ;
// Initialize registers addresses.
subdevice - > ctrl_reg = reg_base + ME4600_AI_CTRL_REG ;
subdevice - > status_reg = reg_base + ME4600_AI_STATUS_REG ;
subdevice - > channel_list_reg = reg_base + ME4600_AI_CHANNEL_LIST_REG ;
subdevice - > data_reg = reg_base + ME4600_AI_DATA_REG ;
subdevice - > chan_timer_reg = reg_base + ME4600_AI_CHAN_TIMER_REG ;
subdevice - > chan_pre_timer_reg = reg_base + ME4600_AI_CHAN_PRE_TIMER_REG ;
subdevice - > scan_timer_low_reg = reg_base + ME4600_AI_SCAN_TIMER_LOW_REG ;
subdevice - > scan_timer_high_reg =
reg_base + ME4600_AI_SCAN_TIMER_HIGH_REG ;
subdevice - > scan_pre_timer_low_reg =
reg_base + ME4600_AI_SCAN_PRE_TIMER_LOW_REG ;
subdevice - > scan_pre_timer_high_reg =
reg_base + ME4600_AI_SCAN_PRE_TIMER_HIGH_REG ;
subdevice - > start_reg = reg_base + ME4600_AI_START_REG ;
subdevice - > irq_status_reg = reg_base + ME4600_IRQ_STATUS_REG ;
subdevice - > sample_counter_reg = reg_base + ME4600_AI_SAMPLE_COUNTER_REG ;
# ifdef MEDEBUG_DEBUG_REG
subdevice - > reg_base = reg_base ;
# endif
// Initialize ranges.
subdevice - > ranges_len = ranges ;
subdevice - > ranges [ 0 ] . min = - 10E6 ;
subdevice - > ranges [ 0 ] . max = 9999694 ;
subdevice - > ranges [ 1 ] . min = 0 ;
subdevice - > ranges [ 1 ] . max = 9999847 ;
subdevice - > ranges [ 2 ] . min = - 25E5 ;
subdevice - > ranges [ 2 ] . max = 2499923 ;
subdevice - > ranges [ 3 ] . min = 0 ;
subdevice - > ranges [ 3 ] . max = 2499961 ;
// We have to switch the mux in order to get it work correctly.
ai_mux_toggler ( subdevice ) ;
// Register interrupt service routine.
subdevice - > irq = irq ;
if ( request_irq ( subdevice - > irq , me4600_ai_isr ,
# ifdef IRQF_DISABLED
IRQF_DISABLED | IRQF_SHARED ,
# else
SA_INTERRUPT | SA_SHIRQ ,
# endif
ME4600_NAME , subdevice ) ) {
PERROR ( " Cannot register interrupt service routine. \n " ) ;
me_subdevice_deinit ( ( me_subdevice_t * ) subdevice ) ;
free_pages ( ( unsigned long ) subdevice - > circ_buf . buf ,
ME4600_AI_CIRC_BUF_SIZE_ORDER ) ;
subdevice - > circ_buf . buf = NULL ;
kfree ( subdevice ) ;
return NULL ;
}
PINFO ( " Registered irq=%d. \n " , subdevice - > irq ) ;
// Override base class methods.
subdevice - > base . me_subdevice_destructor = me4600_ai_destructor ;
subdevice - > base . me_subdevice_io_reset_subdevice =
me4600_ai_io_reset_subdevice ;
subdevice - > base . me_subdevice_io_single_config =
me4600_ai_io_single_config ;
subdevice - > base . me_subdevice_io_single_read = me4600_ai_io_single_read ;
subdevice - > base . me_subdevice_io_stream_config =
me4600_ai_io_stream_config ;
subdevice - > base . me_subdevice_io_stream_new_values =
me4600_ai_io_stream_new_values ;
subdevice - > base . me_subdevice_io_stream_read = me4600_ai_io_stream_read ;
subdevice - > base . me_subdevice_io_stream_start =
me4600_ai_io_stream_start ;
subdevice - > base . me_subdevice_io_stream_status =
me4600_ai_io_stream_status ;
subdevice - > base . me_subdevice_io_stream_stop = me4600_ai_io_stream_stop ;
subdevice - > base . me_subdevice_query_number_channels =
me4600_ai_query_number_channels ;
subdevice - > base . me_subdevice_query_subdevice_type =
me4600_ai_query_subdevice_type ;
subdevice - > base . me_subdevice_query_subdevice_caps =
me4600_ai_query_subdevice_caps ;
subdevice - > base . me_subdevice_query_subdevice_caps_args =
me4600_ai_query_subdevice_caps_args ;
subdevice - > base . me_subdevice_query_range_by_min_max =
me4600_ai_query_range_by_min_max ;
subdevice - > base . me_subdevice_query_number_ranges =
me4600_ai_query_number_ranges ;
subdevice - > base . me_subdevice_query_range_info =
me4600_ai_query_range_info ;
subdevice - > base . me_subdevice_query_timer = me4600_ai_query_timer ;
// Prepare work queue.
subdevice - > me4600_workqueue = me4600_wq ;
/* workqueue API changed in kernel 2.6.20 */
INIT_DELAYED_WORK ( & subdevice - > ai_control_task ,
me4600_ai_work_control_task ) ;
return subdevice ;
}
static void me4600_ai_destructor ( struct me_subdevice * subdevice )
{
me4600_ai_subdevice_t * instance ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance - > ai_control_task_flag = 0 ;
// Reset subdevice to asure clean exit.
me4600_ai_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 - > ai_control_task ) ) { //Wait 2 ticks to be sure that control task is removed from queue.
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_timeout ( 2 ) ;
}
free_irq ( instance - > irq , instance ) ;
free_pages ( ( unsigned long ) instance - > circ_buf . buf ,
ME4600_AI_CIRC_BUF_SIZE_ORDER ) ;
me_subdevice_deinit ( & instance - > base ) ;
kfree ( instance ) ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_reset_subdevice ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep , int flags )
{
me4600_ai_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
volatile uint32_t ctrl ;
unsigned long status ;
const int timeout = HZ / 10 ; //100ms
int i ;
PDEBUG ( " executed. idx=0 \n " ) ;
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
instance = ( me4600_ai_subdevice_t * ) subdevice ;
ME_SUBDEVICE_ENTER ;
instance - > ai_control_task_flag = 0 ;
instance - > status = ai_status_none ;
for ( i = 0 ; i < = timeout ; i + + ) {
spin_lock_irqsave ( instance - > ctrl_reg_lock , status ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
//Stop DMA
ctrl & = ~ ME4600_AI_CTRL_RPCI_FIFO ;
// Stop all actions. No conditions!
ctrl & = ~ ME4600_AI_CTRL_BIT_STOP ;
ctrl | = ME4600_AI_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 - > ctrl_reg_lock , status ) ;
if ( ! ( inl ( instance - > status_reg ) & ME4600_AI_STATUS_BIT_FSM ) )
break ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_timeout ( 1 ) ;
}
if ( i > timeout ) {
PERROR ( " FSM is still busy. \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_INTERNAL ;
}
spin_lock_irqsave ( instance - > ctrl_reg_lock , status ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
// Clear all features. Dissable interrupts.
ctrl & = ~ ( ME4600_AI_CTRL_BIT_STOP
| ME4600_AI_CTRL_BIT_LE_IRQ
| ME4600_AI_CTRL_BIT_HF_IRQ | ME4600_AI_CTRL_BIT_SC_IRQ ) ;
ctrl | = ( ME4600_AI_CTRL_BIT_IMMEDIATE_STOP
| ME4600_AI_CTRL_BIT_LE_IRQ_RESET
| ME4600_AI_CTRL_BIT_HF_IRQ_RESET
| ME4600_AI_CTRL_BIT_SC_IRQ_RESET ) ;
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 - > ctrl_reg_lock , status ) ;
outl ( ME4600_AI_MIN_CHAN_TICKS - 1 , instance - > chan_timer_reg ) ;
PDEBUG_REG ( " chan_timer_reg outl(0x%lX+0x%lX)=0x%llx \n " ,
instance - > reg_base ,
instance - > chan_timer_reg - instance - > reg_base ,
ME4600_AI_MIN_CHAN_TICKS ) ;
outl ( ME4600_AI_MIN_ACQ_TICKS - 1 , instance - > chan_pre_timer_reg ) ;
PDEBUG_REG ( " chan_pre_timer_reg outl(0x%lX+0x%lX)=0x%llx \n " ,
instance - > reg_base ,
instance - > chan_pre_timer_reg - instance - > reg_base ,
ME4600_AI_MIN_ACQ_TICKS ) ;
outl ( 0 , instance - > scan_timer_low_reg ) ;
PDEBUG_REG ( " scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_low_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_timer_high_reg ) ;
PDEBUG_REG ( " scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_high_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_pre_timer_low_reg ) ;
PDEBUG_REG ( " scan_pre_timer_low_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_pre_timer_low_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_pre_timer_high_reg ) ;
PDEBUG_REG ( " scan_pre_timer_high_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_pre_timer_high_reg - instance - > reg_base , 0 ) ;
outl ( 0xEFFFFFFF , instance - > sample_counter_reg ) ;
PDEBUG_REG ( " sample_counter_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > sample_counter_reg - instance - > reg_base ,
0xEFFFFFFF ) ;
instance - > circ_buf . head = 0 ;
instance - > circ_buf . tail = 0 ;
instance - > fifo_irq_threshold = 0 ;
instance - > data_required = 0 ;
instance - > chan_list_len = 0 ;
// Initialize the single config entries to reset values.
for ( i = 0 ; i < instance - > channels ; i + + ) {
instance - > single_config [ i ] . status =
ME_SINGLE_CHANNEL_NOT_CONFIGURED ;
}
instance - > status = ai_status_none ;
//Signal reset if user is on wait.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
ME_SUBDEVICE_EXIT ;
return err ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_single_config ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int channel ,
int single_config ,
int ref ,
int trig_chan ,
int trig_type , int trig_edge , int flags )
{
me4600_ai_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
unsigned long cpu_flags ;
int i ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=0 \n " ) ;
if ( flags & ~ ME_IO_SINGLE_CONFIG_CONTINUE ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
switch ( trig_type ) {
case ME_TRIG_TYPE_SW :
if ( trig_edge ! = ME_TRIG_EDGE_NONE ) {
PERROR
( " Invalid trigger edge. Software trigger has not edge. \n " ) ;
return ME_ERRNO_INVALID_TRIG_EDGE ;
}
break ;
case ME_TRIG_TYPE_EXT_ANALOG :
if ( instance - > channels < = 16 ) //Only versions with 32 channels have analog trigger (4670 and 4680)
{
PERROR ( " Invalid trigger type specified. \n " ) ;
return ME_ERRNO_INVALID_TRIG_TYPE ;
}
case ME_TRIG_TYPE_EXT_DIGITAL :
if ( ( trig_edge ! = ME_TRIG_EDGE_ANY )
& & ( trig_edge ! = ME_TRIG_EDGE_RISING )
& & ( trig_edge ! = ME_TRIG_EDGE_FALLING ) ) {
PERROR ( " Invalid trigger edge specified. \n " ) ;
return ME_ERRNO_INVALID_TRIG_EDGE ;
}
break ;
default :
PERROR ( " Invalid trigger type specified. \n " ) ;
return ME_ERRNO_INVALID_TRIG_TYPE ;
}
if ( trig_chan ! = ME_TRIG_CHAN_DEFAULT ) {
PERROR ( " Invalid trigger channel specified. \n " ) ;
return ME_ERRNO_INVALID_TRIG_CHAN ;
}
if ( ( single_config < 0 ) | | ( single_config > = instance - > ranges_len ) ) {
PERROR ( " Invalid single config specified. \n " ) ;
return ME_ERRNO_INVALID_SINGLE_CONFIG ;
}
if ( ( ref ! = ME_REF_AI_GROUND ) & & ( ref ! = ME_REF_AI_DIFFERENTIAL ) ) {
PERROR ( " Invalid analog reference specified. \n " ) ;
return ME_ERRNO_INVALID_REF ;
}
if ( ( single_config % 2 ) & & ( ref ! = ME_REF_AI_GROUND ) ) {
PERROR ( " Invalid analog reference specified. \n " ) ;
return ME_ERRNO_INVALID_REF ;
}
if ( ( ref = = ME_REF_AI_DIFFERENTIAL )
& & ( ( instance - > channels = = 16 ) | | ( channel > = 16 ) ) ) {
PERROR ( " Invalid analog reference specified. \n " ) ;
return ME_ERRNO_INVALID_REF ;
}
if ( channel < 0 ) {
PERROR ( " Invalid channel number specified. \n " ) ;
return ME_ERRNO_INVALID_CHANNEL ;
}
if ( channel > = instance - > channels ) {
PERROR ( " Invalid channel number specified. \n " ) ;
return ME_ERRNO_INVALID_CHANNEL ;
}
ME_SUBDEVICE_ENTER ;
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
//Prepare data entry.
// Common for all modes.
instance - > single_config [ channel ] . entry =
channel | ME4600_AI_LIST_LAST_ENTRY ;
if ( ref = = ME_REF_AI_DIFFERENTIAL ) { // ME_REF_AI_DIFFERENTIAL
instance - > single_config [ channel ] . entry | =
ME4600_AI_LIST_INPUT_DIFFERENTIAL ;
}
/*
// ME4600_AI_LIST_INPUT_SINGLE_ENDED = 0x0000
// 'entry |= ME4600_AI_LIST_INPUT_SINGLE_ENDED' <== Do nothing. Removed.
else
{ // ME_REF_AI_GROUND
instance - > single_config [ channel ] . entry | = ME4600_AI_LIST_INPUT_SINGLE_ENDED ;
}
*/
switch ( single_config ) {
case 0 : //-10V..10V
/*
// ME4600_AI_LIST_RANGE_BIPOLAR_10 = 0x0000
// 'entry |= ME4600_AI_LIST_RANGE_BIPOLAR_10' <== Do nothing. Removed.
instance - > single_config [ channel ] . entry | = ME4600_AI_LIST_RANGE_BIPOLAR_10 ;
*/ break ;
case 1 : //0V..10V
instance - > single_config [ channel ] . entry | =
ME4600_AI_LIST_RANGE_UNIPOLAR_10 ;
break ;
case 2 : //-2.5V..2.5V
instance - > single_config [ channel ] . entry | =
ME4600_AI_LIST_RANGE_BIPOLAR_2_5 ;
break ;
case 3 : //0V..2.5V
instance - > single_config [ channel ] . entry | =
ME4600_AI_LIST_RANGE_UNIPOLAR_2_5 ;
break ;
}
// Prepare control register.
// Common for all modes.
instance - > single_config [ channel ] . ctrl =
ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO ;
switch ( trig_type ) {
case ME_TRIG_TYPE_SW :
// Nothing to set.
break ;
case ME_TRIG_TYPE_EXT_ANALOG :
instance - > single_config [ channel ] . ctrl | =
ME4600_AI_CTRL_BIT_EX_TRIG_ANALOG ;
case ME_TRIG_TYPE_EXT_DIGITAL :
instance - > single_config [ channel ] . ctrl | =
ME4600_AI_CTRL_BIT_EX_TRIG ;
break ;
}
switch ( trig_edge ) {
case ME_TRIG_EDGE_RISING :
// Nothing to set.
break ;
case ME_TRIG_EDGE_ANY :
instance - > single_config [ channel ] . ctrl | =
ME4600_AI_CTRL_BIT_EX_TRIG_BOTH ;
case ME_TRIG_EDGE_FALLING :
instance - > single_config [ channel ] . ctrl | =
ME4600_AI_CTRL_BIT_EX_TRIG_FALLING ;
break ;
}
// Enable this channel
instance - > single_config [ channel ] . status = ME_SINGLE_CHANNEL_CONFIGURED ;
// Copy this settings to other outputs.
if ( flags = = ME_IO_SINGLE_CONFIG_CONTINUE ) {
for ( i = channel + 1 ; i < instance - > channels ; i + + ) {
instance - > single_config [ i ] . ctrl =
instance - > single_config [ channel ] . ctrl ;
instance - > single_config [ i ] . entry =
instance - > single_config [ channel ] . entry ;
instance - > single_config [ i ] . status =
ME_SINGLE_CHANNEL_CONFIGURED ;
}
}
instance - > status = ai_status_single_configured ;
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
ME_SUBDEVICE_EXIT ;
return err ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_single_read ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int channel ,
int * value , int time_out , int flags )
{
me4600_ai_subdevice_t * instance ;
volatile uint32_t tmp ;
volatile uint32_t val ;
unsigned long cpu_flags ;
int err = ME_ERRNO_SUCCESS ;
unsigned long j ;
unsigned long delay = 0 ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( instance - > status ! = ai_status_single_configured ) {
PERROR ( " Subdevice not configured to work in single mode! \n " ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
}
if ( ( channel > instance - > channels ) | | ( channel < 0 ) ) {
PERROR ( " Invalid channel specified. \n " ) ;
return ME_ERRNO_INVALID_CHANNEL ;
}
if ( time_out < 0 ) {
PERROR ( " Invalid timeout specified. \n " ) ;
return ME_ERRNO_INVALID_TIMEOUT ;
}
if ( instance - > single_config [ channel ] . status ! =
ME_SINGLE_CHANNEL_CONFIGURED ) {
PERROR ( " Channel is not configured to work in single mode! \n " ) ;
return ME_ERRNO_PREVIOUS_CONFIG ;
}
if ( inl ( instance - > status_reg ) & ME4600_AI_STATUS_BIT_FSM ) {
PERROR ( " Subdevice is busy. \n " ) ;
return ME_ERRNO_SUBDEVICE_BUSY ;
}
ME_SUBDEVICE_ENTER ;
// Cancel control task
PDEBUG ( " Cancel control task. \n " ) ;
instance - > ai_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ai_control_task ) ;
if ( time_out ) {
delay = ( time_out * HZ ) / 1000 ;
if ( delay = = 0 )
delay = 1 ;
}
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
// Mark that StreamConfig is removed.
instance - > chan_list_len = 0 ;
spin_lock_irqsave ( instance - > ctrl_reg_lock , cpu_flags ) ;
/// @note Imprtant: Preserve EXT IRQ settings.
tmp = inl ( instance - > ctrl_reg ) ;
// Clear FIFOs and dissable interrupts
tmp & =
~ ( ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO ) ;
tmp & =
~ ( ME4600_AI_CTRL_BIT_SC_IRQ | ME4600_AI_CTRL_BIT_HF_IRQ |
ME4600_AI_CTRL_BIT_LE_IRQ ) ;
tmp | =
ME4600_AI_CTRL_BIT_SC_IRQ_RESET | ME4600_AI_CTRL_BIT_HF_IRQ_RESET |
ME4600_AI_CTRL_BIT_LE_IRQ_RESET ;
tmp | = ME4600_AI_CTRL_BIT_IMMEDIATE_STOP ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
outl ( 0 , instance - > scan_pre_timer_low_reg ) ;
PDEBUG_REG ( " scan_pre_timer_low_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_pre_timer_low_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_pre_timer_high_reg ) ;
PDEBUG_REG ( " scan_pre_timer_high_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_pre_timer_high_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_timer_low_reg ) ;
PDEBUG_REG ( " scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_low_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_timer_high_reg ) ;
PDEBUG_REG ( " scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_high_reg - instance - > reg_base , 0 ) ;
outl ( 65 , instance - > chan_timer_reg ) ;
PDEBUG_REG ( " chan_timer_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > chan_timer_reg - instance - > reg_base , 65 ) ;
outl ( 65 , instance - > chan_pre_timer_reg ) ;
PDEBUG_REG ( " chan_pre_timer_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > chan_pre_timer_reg - instance - > reg_base , 65 ) ;
//Reactive FIFOs. Enable work.
tmp | = ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
outl ( instance - > single_config [ channel ] . entry ,
instance - > channel_list_reg ) ;
PDEBUG_REG ( " channel_list_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > channel_list_reg - instance - > reg_base ,
instance - > single_config [ channel ] . entry ) ;
// Preserve EXT IRQ settings.
tmp & = ( ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET ) ;
outl ( instance - > single_config [ channel ] . ctrl | tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
instance - > single_config [ channel ] . ctrl | tmp ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
if ( ! ( instance - > single_config [ channel ] . ctrl & ME4600_AI_CTRL_BIT_EX_TRIG ) ) { // Software start
inl ( instance - > start_reg ) ;
PDEBUG_REG ( " start_reg inl(0x%lX+0x%lX) \n " , instance - > reg_base ,
instance - > start_reg - instance - > reg_base ) ;
delay = 2 ;
}
j = jiffies ;
while ( ! ( inl ( instance - > status_reg ) & ME4600_AI_STATUS_BIT_EF_DATA ) ) {
if ( delay & & ( ( jiffies - j ) > = delay ) ) {
if ( ! ( instance - > single_config [ channel ] . ctrl & ME4600_AI_CTRL_BIT_EX_TRIG ) ) { // Software start.
PERROR ( " Value not available after wait. \n " ) ;
err = ME_ERRNO_INTERNAL ;
} else { // External start.
PERROR ( " Timeout reached. \n " ) ;
err = ME_ERRNO_TIMEOUT ;
}
break ;
}
// Wait
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_timeout ( 1 ) ;
if ( signal_pending ( current ) ) {
PERROR
( " Wait on external trigger interrupted by signal. \n " ) ;
err = ME_ERRNO_SIGNAL ;
break ;
}
if ( instance - > status ! = ai_status_single_configured ) {
PERROR ( " Wait interrupted by reset. \n " ) ;
err = ME_ERRNO_CANCELLED ;
break ;
}
}
// Read value.
if ( ! err ) {
val = inl ( instance - > data_reg ) ^ 0x8000 ;
PDEBUG_REG ( " data_reg inl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > data_reg - instance - > reg_base , val ) ;
* value = val & ME4600_AI_MAX_DATA ;
} else {
* value = 0xFFFFFFFF ;
}
// Restore settings.
spin_lock_irqsave ( instance - > ctrl_reg_lock , cpu_flags ) ;
tmp = inl ( instance - > ctrl_reg ) ;
// Clear FIFOs and dissable interrupts.
tmp & =
~ ( ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO ) ;
tmp | = ME4600_AI_CTRL_BIT_SC_IRQ | ME4600_AI_CTRL_BIT_HF_IRQ ;
tmp | =
ME4600_AI_CTRL_BIT_SC_IRQ_RESET | ME4600_AI_CTRL_BIT_HF_IRQ_RESET |
ME4600_AI_CTRL_BIT_LE_IRQ_RESET | ME4600_AI_CTRL_BIT_IMMEDIATE_STOP ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
ME_SUBDEVICE_EXIT ;
return err ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_config ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
2009-03-16 17:45:13 +01:00
meIOStreamConfig_t * config_list ,
2008-11-01 00:39:12 +01:00
int count ,
2009-03-16 17:45:13 +01:00
meIOStreamTrigger_t * trigger ,
2008-11-01 00:39:12 +01:00
int fifo_irq_threshold , int flags )
{
me4600_ai_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
int i ; // internal multipurpose variable
unsigned long long data_required ;
volatile uint32_t entry ;
volatile uint32_t ctrl = ME4600_AI_CTRL_BIT_IMMEDIATE_STOP ;
volatile uint32_t tmp ; // use when current copy of register's value needed
unsigned long cpu_flags ;
uint64_t acq_ticks ;
uint64_t scan_ticks ;
uint64_t conv_ticks ;
unsigned int acq_start_ticks_low = trigger - > iAcqStartTicksLow ;
unsigned int acq_start_ticks_high = trigger - > iAcqStartTicksHigh ;
unsigned int scan_start_ticks_low = trigger - > iScanStartTicksLow ;
unsigned int scan_start_ticks_high = trigger - > iScanStartTicksHigh ;
unsigned int conv_start_ticks_low = trigger - > iConvStartTicksLow ;
unsigned int conv_start_ticks_high = trigger - > iConvStartTicksHigh ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
ME_SUBDEVICE_ENTER
// Convert ticks to 64 bit long values
acq_ticks =
( uint64_t ) acq_start_ticks_low +
( ( uint64_t ) acq_start_ticks_high < < 32 ) ;
scan_ticks =
( uint64_t ) scan_start_ticks_low +
( ( uint64_t ) scan_start_ticks_high < < 32 ) ;
conv_ticks =
( uint64_t ) conv_start_ticks_low +
( ( uint64_t ) conv_start_ticks_high < < 32 ) ;
// Check settings - begin
switch ( trigger - > iAcqStartTrigType ) {
case ME_TRIG_TYPE_SW :
case ME_TRIG_TYPE_EXT_DIGITAL :
case ME_TRIG_TYPE_EXT_ANALOG :
break ;
default :
PERROR ( " Invalid acquisition start trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE ;
goto ERROR ;
break ;
}
if ( ( trigger - > iAcqStartTrigType = = ME_TRIG_TYPE_SW )
& & ( trigger - > iAcqStartTrigEdge ! = ME_TRIG_EDGE_NONE ) ) {
PERROR ( " Invalid acquisition start trigger edge specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE ;
goto ERROR ;
}
if ( trigger - > iAcqStartTrigType ! = ME_TRIG_TYPE_SW ) {
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 " ) ;
err = ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE ;
goto ERROR ;
break ;
}
}
if ( trigger - > iAcqStartTrigChan ! = ME_TRIG_CHAN_DEFAULT ) {
PERROR
( " Invalid acquisition start trigger channel specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_START_TRIG_CHAN ;
goto ERROR ;
}
if ( ( acq_ticks < ME4600_AI_MIN_ACQ_TICKS )
| | ( acq_ticks > ME4600_AI_MAX_ACQ_TICKS ) ) {
PERROR
( " Invalid acquisition start trigger argument specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_START_ARG ;
goto ERROR ;
}
switch ( trigger - > iScanStartTrigType ) {
case ME_TRIG_TYPE_TIMER :
if ( ( scan_ticks < ME4600_AI_MIN_SCAN_TICKS )
| | ( scan_ticks > ME4600_AI_MAX_SCAN_TICKS )
| | ( scan_ticks < count * conv_ticks )
) {
PERROR ( " Invalid scan start argument specified. \n " ) ;
err = ME_ERRNO_INVALID_SCAN_START_ARG ;
goto ERROR ;
}
break ;
case ME_TRIG_TYPE_EXT_DIGITAL :
if ( trigger - > iAcqStartTrigType ! = ME_TRIG_TYPE_EXT_DIGITAL ) {
PERROR
( " Invalid scan start trigger type specified (Acq is HW digital) \n " ) ;
err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE ;
goto ERROR ;
}
break ;
case ME_TRIG_TYPE_EXT_ANALOG :
if ( trigger - > iAcqStartTrigType ! = ME_TRIG_TYPE_EXT_ANALOG ) {
PERROR
( " Invalid scan start trigger type specified (Acq is HW analog) \n " ) ;
err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE ;
goto ERROR ;
}
break ;
case ME_TRIG_TYPE_FOLLOW :
break ;
default :
PERROR ( " Invalid scan start trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE ;
goto ERROR ;
break ;
}
switch ( trigger - > iConvStartTrigType ) {
case ME_TRIG_TYPE_TIMER :
if ( ( conv_ticks < ME4600_AI_MIN_CHAN_TICKS )
| | ( conv_ticks > ME4600_AI_MAX_CHAN_TICKS ) ) {
PERROR
( " Invalid conv start trigger argument specified. \n " ) ;
err = ME_ERRNO_INVALID_CONV_START_ARG ;
goto ERROR ;
}
break ;
case ME_TRIG_TYPE_EXT_DIGITAL :
if ( ( trigger - > iScanStartTrigType ! = ME_TRIG_TYPE_FOLLOW )
| | ( trigger - > iAcqStartTrigType ! =
ME_TRIG_TYPE_EXT_DIGITAL ) ) {
PERROR ( " Invalid conv start trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE ;
goto ERROR ;
}
break ;
case ME_TRIG_TYPE_EXT_ANALOG :
if ( ( trigger - > iScanStartTrigType ! = ME_TRIG_TYPE_FOLLOW )
| | ( trigger - > iAcqStartTrigType ! =
ME_TRIG_TYPE_EXT_ANALOG ) ) {
PERROR ( " Invalid conv start trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE ;
goto ERROR ;
}
break ;
default :
PERROR ( " Invalid conv start trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE ;
goto ERROR ;
break ;
}
/**
* Aceptable settings :
* iScanStopTrigType : iAcqStopTrigType
*
* ME_TRIG_TYPE_NONE : ME_TRIG_TYPE_NONE - > infinite count with manual stop
* ME_TRIG_TYPE_NONE : ME_TRIG_TYPE_COUNT - > stop after getting iScanStopCount list of values ( iScanStopCount * count )
* ME_TRIG_TYPE_COUNT : ME_TRIG_TYPE_FOLLOW - > stop after getting iAcqStopCount values ( it can stops in midle of the list )
*/
switch ( trigger - > iScanStopTrigType ) {
case ME_TRIG_TYPE_NONE :
break ;
case ME_TRIG_TYPE_COUNT :
if ( trigger - > iScanStopCount < = 0 ) {
PERROR ( " Invalid scan stop argument specified. \n " ) ;
err = ME_ERRNO_INVALID_SCAN_STOP_ARG ;
goto ERROR ;
}
break ;
default :
PERROR ( " Invalid scan stop trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_SCAN_STOP_TRIG_TYPE ;
goto ERROR ;
break ;
}
switch ( trigger - > iAcqStopTrigType ) {
case ME_TRIG_TYPE_NONE :
if ( trigger - > iScanStopTrigType ! = ME_TRIG_TYPE_NONE ) {
PERROR ( " Invalid acq stop trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE ;
goto ERROR ;
}
break ;
case ME_TRIG_TYPE_FOLLOW :
if ( trigger - > iScanStopTrigType ! = ME_TRIG_TYPE_COUNT ) {
PERROR ( " Invalid acq stop trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE ;
goto ERROR ;
}
break ;
case ME_TRIG_TYPE_COUNT :
if ( trigger - > iScanStopTrigType ! = ME_TRIG_TYPE_NONE ) {
PERROR ( " Invalid acq stop trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE ;
goto ERROR ;
}
if ( trigger - > iAcqStopCount < = 0 ) {
PERROR
( " Invalid acquisition or scan stop argument specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_STOP_ARG ;
goto ERROR ;
}
break ;
default :
PERROR ( " Invalid acq stop trigger type specified. \n " ) ;
err = ME_ERRNO_INVALID_ACQ_STOP_TRIG_TYPE ;
goto ERROR ;
break ;
}
if ( ( count < = 0 ) | | ( count > ME4600_AI_LIST_COUNT ) ) {
PERROR ( " Invalid channel list count specified. \n " ) ;
err = ME_ERRNO_INVALID_CONFIG_LIST_COUNT ;
goto ERROR ;
}
///This is general limitation
// if (fifo_irq_threshold < 0 || fifo_irq_threshold >= ME4600_AI_CIRC_BUF_COUNT)
///This is limitation from Windows. I use it for compatibility.
if ( fifo_irq_threshold < 0
| | fifo_irq_threshold > = ME4600_AI_FIFO_COUNT ) {
PERROR ( " Invalid fifo irq threshold specified. \n " ) ;
err = ME_ERRNO_INVALID_FIFO_IRQ_THRESHOLD ;
goto ERROR ;
}
if ( ( config_list [ 0 ] . iRef = = ME_REF_AI_DIFFERENTIAL )
& & ( instance - > channels = = 16 ) ) {
PERROR
( " Differential reference is not available on this subdevice. \n " ) ;
err = ME_ERRNO_INVALID_REF ;
goto ERROR ;
}
if ( flags & ME_IO_STREAM_CONFIG_SAMPLE_AND_HOLD ) {
if ( ! instance - > sh ) {
PERROR
( " Sample and hold is not available for this board. \n " ) ;
err = ME_ERRNO_INVALID_FLAGS ;
goto ERROR ;
}
if ( config_list [ 0 ] . iRef = = ME_REF_AI_DIFFERENTIAL ) {
PERROR
( " Sample and hold is not available in differential mode. \n " ) ;
err = ME_ERRNO_INVALID_FLAGS ;
goto ERROR ;
}
}
for ( i = 0 ; i < count ; i + + ) {
if ( ( config_list [ i ] . iStreamConfig < 0 )
| | ( config_list [ i ] . iStreamConfig > = instance - > ranges_len ) ) {
PERROR ( " Invalid stream config specified. \n " ) ;
err = ME_ERRNO_INVALID_STREAM_CONFIG ;
goto ERROR ;
}
if ( ( config_list [ i ] . iRef ! = ME_REF_AI_GROUND )
& & ( config_list [ i ] . iRef ! = ME_REF_AI_DIFFERENTIAL ) ) {
PERROR ( " Invalid references in the list. Ref=0x%x \n " ,
config_list [ i ] . iRef ) ;
err = ME_ERRNO_INVALID_REF ;
goto ERROR ;
}
if ( config_list [ i ] . iStreamConfig % 2 ) { // StreamConfig: 1 or 3
if ( config_list [ i ] . iRef = = ME_REF_AI_DIFFERENTIAL ) {
PERROR
( " Only bipolar modes support differential measurement. \n " ) ;
err = ME_ERRNO_INVALID_REF ;
goto ERROR ;
}
}
if ( config_list [ i ] . iRef ! = config_list [ 0 ] . iRef ) {
PERROR
( " Not all references in the configuration list are equal. Ref[0]=0x%x Ref[%d]=0x%x \n " ,
config_list [ 0 ] . iRef , i , config_list [ i ] . iRef ) ;
err = ME_ERRNO_INVALID_REF ;
goto ERROR ;
}
if ( ( config_list [ i ] . iRef = = ME_REF_AI_DIFFERENTIAL )
& & ( config_list [ i ] . iChannel > = 16 ) ) {
PERROR ( " Channel not available in differential mode. \n " ) ;
err = ME_ERRNO_INVALID_CHANNEL ;
goto ERROR ;
}
if ( ( config_list [ i ] . iChannel < 0 )
| | ( config_list [ i ] . iChannel > = instance - > channels ) ) {
PERROR ( " Invalid channel number specified. \n " ) ;
err = ME_ERRNO_INVALID_CHANNEL ;
goto ERROR ;
}
}
// Check settings - end
//Cancel control task
PDEBUG ( " Cancel control task. \n " ) ;
instance - > ai_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ai_control_task ) ;
// Work around from Keith Hartley - begin
if ( trigger - > iScanStartTrigType = = ME_TRIG_TYPE_TIMER ) {
if ( count = = 1 ) {
// The hardware does not work properly with a non-zero scan time
// if there is only ONE channel in the channel list. In this case
// we must set the scan time to zero and use the channel time.
conv_ticks = scan_ticks ;
trigger - > iScanStartTrigType = ME_TRIG_TYPE_FOLLOW ;
} else if ( scan_ticks = = count * conv_ticks ) {
// Another hardware problem. If the number of scan ticks is
// exactly equal to the number of channel ticks multiplied by
// the number of channels then the sampling rate is reduced
// by half.
trigger - > iScanStartTrigType = ME_TRIG_TYPE_FOLLOW ;
}
}
// Work around from Keith Hartley - end
spin_lock_irqsave ( & instance - > subdevice_lock , cpu_flags ) ;
if ( inl ( instance - > status_reg ) & ME4600_AI_STATUS_BIT_FSM ) {
PERROR ( " Subdevice is busy. \n " ) ;
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_SUBDEVICE_BUSY ;
}
instance - > status = ai_status_none ;
spin_lock_irqsave ( instance - > ctrl_reg_lock , cpu_flags ) ;
// Stop all actions. Block all interrupts. Clear (disable) FIFOs.
ctrl =
ME4600_AI_CTRL_BIT_LE_IRQ_RESET | ME4600_AI_CTRL_BIT_HF_IRQ_RESET |
ME4600_AI_CTRL_BIT_SC_IRQ_RESET ;
tmp = inl ( instance - > ctrl_reg ) ;
// Preserve EXT IRQ and OFFSET settings. Clean other bits.
tmp & =
( ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET |
ME4600_AI_CTRL_BIT_FULLSCALE | ME4600_AI_CTRL_BIT_OFFSET ) ;
// Send it to register.
outl ( tmp | 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 , tmp | ctrl ) ;
// Enable channel fifo -> data fifo in stream_start().
ctrl | = ME4600_AI_CTRL_BIT_CHANNEL_FIFO ;
outl ( tmp | 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 , tmp | ctrl ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
// Write the channel list
for ( i = 0 ; i < count ; i + + ) {
entry = config_list [ i ] . iChannel ;
switch ( config_list [ i ] . iStreamConfig ) {
case 0 : //BIPOLAR 10V
/*
// ME4600_AI_LIST_RANGE_BIPOLAR_10 = 0x0000
// 'entry |= ME4600_AI_LIST_RANGE_BIPOLAR_10' <== Do nothing. Removed.
entry | = ME4600_AI_LIST_RANGE_BIPOLAR_10 ;
*/
break ;
case 1 : //UNIPOLAR 10V
entry | = ME4600_AI_LIST_RANGE_UNIPOLAR_10 ;
break ;
case 2 : //BIPOLAR 2.5V
entry | = ME4600_AI_LIST_RANGE_BIPOLAR_2_5 ;
break ;
case 3 : //UNIPOLAR 2.5V
entry | = ME4600_AI_LIST_RANGE_UNIPOLAR_2_5 ;
break ;
default :
PERROR_CRITICAL ( " UNCHECK ERROR in config_list! \n " ) ;
PERROR_CRITICAL
( " WRONG range \n Position:%d Range:0x%04X \n " , i ,
config_list [ i ] . iStreamConfig ) ;
goto VERIFY_ERROR ;
break ;
}
switch ( config_list [ i ] . iRef ) {
case ME_REF_AI_GROUND : //SINGLE ENDED
/*
// ME4600_AI_LIST_INPUT_SINGLE_ENDED = 0x0000
// 'entry |= ME4600_AI_LIST_INPUT_SINGLE_ENDED' ==> Do nothing. Removed.
entry | = ME4600_AI_LIST_INPUT_SINGLE_ENDED ;
*/ break ;
case ME_REF_AI_DIFFERENTIAL : //DIFFERENTIAL
entry | = ME4600_AI_LIST_INPUT_DIFFERENTIAL ;
break ;
default :
PERROR_CRITICAL ( " UNCHECK ERROR in config_list! \n " ) ;
PERROR_CRITICAL
( " WRONG reference \n Position:%d Reference:0x%04X \n " ,
i , config_list [ i ] . iRef ) ;
goto VERIFY_ERROR ;
break ;
}
//Add last entry flag
if ( i = = ( count - 1 ) ) {
entry | = ME4600_AI_LIST_LAST_ENTRY ;
}
outl ( entry , instance - > channel_list_reg ) ;
PDEBUG_REG ( " channel_list_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > channel_list_reg - instance - > reg_base ,
entry ) ;
}
// Set triggering registers
- - acq_ticks ;
outl ( acq_ticks , instance - > chan_pre_timer_reg ) ;
PDEBUG_REG ( " chan_pre_timer_reg outl(0x%lX+0x%lX)=0x%llX \n " ,
instance - > reg_base ,
instance - > chan_pre_timer_reg - instance - > reg_base ,
acq_ticks ) ;
outl ( acq_ticks , instance - > scan_pre_timer_low_reg ) ;
PDEBUG_REG ( " scan_pre_timer_low_reg outl(0x%lX+0x%lX)=0x%llX \n " ,
instance - > reg_base ,
instance - > scan_pre_timer_low_reg - instance - > reg_base ,
acq_ticks & 0xFFFFFFFF ) ;
outl ( ( acq_ticks > > 32 ) , instance - > scan_pre_timer_high_reg ) ;
PDEBUG_REG ( " scan_pre_timer_high_reg outl(0x%lX+0x%lX)=0x%llX \n " ,
instance - > reg_base ,
instance - > scan_pre_timer_high_reg - instance - > reg_base ,
( acq_ticks > > 32 ) & 0xFFFFFFFF ) ;
// Set triggers
switch ( trigger - > iAcqStartTrigType ) {
// Internal
case ME_TRIG_TYPE_SW :
// Nothing to set.
break ;
// External
case ME_TRIG_TYPE_EXT_ANALOG :
ctrl | = ME4600_AI_CTRL_BIT_EX_TRIG_ANALOG ;
case ME_TRIG_TYPE_EXT_DIGITAL :
ctrl | = ME4600_AI_CTRL_BIT_EX_TRIG ;
// External trigger needs edge's definition
switch ( trigger - > iAcqStartTrigEdge ) {
case ME_TRIG_EDGE_RISING :
// Nothing to set.
break ;
case ME_TRIG_EDGE_FALLING :
ctrl | = ME4600_AI_CTRL_BIT_EX_TRIG_FALLING ;
break ;
case ME_TRIG_EDGE_ANY :
ctrl | =
ME4600_AI_CTRL_BIT_EX_TRIG_FALLING |
ME4600_AI_CTRL_BIT_EX_TRIG_BOTH ;
break ;
default :
PERROR_CRITICAL
( " UNCHECK TRIGGER EDGE in triggers structure! \n " ) ;
PERROR_CRITICAL
( " WRONG acquisition start trigger:0x%04X. \n " ,
trigger - > iAcqStartTrigEdge ) ;
err = ME_ERRNO_INVALID_ACQ_START_TRIG_EDGE ;
goto VERIFY_ERROR ;
break ;
}
break ;
default :
PERROR_CRITICAL ( " UNCHECK TRIGGER in triggers structure! \n " ) ;
PERROR_CRITICAL ( " WRONG acquisition start trigger:0x%04X. \n " ,
trigger - > iAcqStartTrigType ) ;
err = ME_ERRNO_INVALID_ACQ_START_TRIG_TYPE ;
goto VERIFY_ERROR ;
break ;
}
switch ( trigger - > iScanStartTrigType ) {
case ME_TRIG_TYPE_TIMER :
- - scan_ticks ;
outl ( scan_ticks , instance - > scan_timer_low_reg ) ;
PDEBUG_REG ( " scan_timer_low_reg outl(0x%lX+0x%lX)=0x%llX \n " ,
instance - > reg_base ,
instance - > scan_timer_low_reg - instance - > reg_base ,
scan_ticks & 0xFFFFFFFF ) ;
outl ( ( scan_ticks > > 32 ) , instance - > scan_timer_high_reg ) ;
PDEBUG_REG ( " scan_timer_high_reg outl(0x%lX+0x%lX)=0x%llX \n " ,
instance - > reg_base ,
instance - > scan_timer_high_reg - instance - > reg_base ,
( scan_ticks > > 32 ) & 0xFFFFFFFF ) ;
if ( trigger - > iAcqStartTrigType = = ME_TRIG_TYPE_SW ) {
ctrl | = ME4600_AI_CTRL_BIT_MODE_0 ;
} else {
ctrl | = ME4600_AI_CTRL_BIT_MODE_1 ;
}
break ;
case ME_TRIG_TYPE_EXT_DIGITAL :
case ME_TRIG_TYPE_EXT_ANALOG :
outl ( 0 , instance - > scan_timer_low_reg ) ;
PDEBUG_REG ( " scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_low_reg - instance - > reg_base ,
0 ) ;
outl ( 0 , instance - > scan_timer_high_reg ) ;
PDEBUG_REG ( " scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_high_reg - instance - > reg_base ,
0 ) ;
ctrl | = ME4600_AI_CTRL_BIT_MODE_2 ;
break ;
case ME_TRIG_TYPE_FOLLOW :
outl ( 0 , instance - > scan_timer_low_reg ) ;
PDEBUG_REG ( " scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_low_reg - instance - > reg_base ,
0 ) ;
outl ( 0 , instance - > scan_timer_high_reg ) ;
PDEBUG_REG ( " scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_high_reg - instance - > reg_base ,
0 ) ;
if ( trigger - > iAcqStartTrigType = = ME_TRIG_TYPE_SW ) {
ctrl | = ME4600_AI_CTRL_BIT_MODE_0 ;
} else {
ctrl | = ME4600_AI_CTRL_BIT_MODE_1 ;
}
break ;
default :
PERROR_CRITICAL ( " UNCHECK TRIGGER in triggers structure! \n " ) ;
PERROR_CRITICAL ( " WRONG scan start trigger:0x%04X. \n " ,
trigger - > iScanStartTrigType ) ;
err = ME_ERRNO_INVALID_SCAN_START_TRIG_TYPE ;
goto VERIFY_ERROR ;
break ;
}
switch ( trigger - > iConvStartTrigType ) {
case ME_TRIG_TYPE_TIMER :
- - conv_ticks ;
outl ( conv_ticks , instance - > chan_timer_reg ) ;
PDEBUG_REG ( " chan_timer_reg outl(0x%lX+0x%lX)=0x%llX \n " ,
instance - > reg_base ,
instance - > chan_timer_reg - instance - > reg_base ,
conv_ticks ) ;
break ;
case ME_TRIG_TYPE_EXT_DIGITAL :
case ME_TRIG_TYPE_EXT_ANALOG :
outl ( 0 , instance - > chan_timer_reg ) ;
PDEBUG_REG ( " chan_timer_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > chan_timer_reg - instance - > reg_base , 0 ) ;
ctrl | = ME4600_AI_CTRL_BIT_MODE_0 | ME4600_AI_CTRL_BIT_MODE_1 ;
break ;
default :
PERROR_CRITICAL ( " UNCHECK TRIGGER in triggers structure! \n " ) ;
PERROR_CRITICAL ( " WRONG conv start trigger:0x%04X. \n " ,
trigger - > iConvStartTrigType ) ;
err = ME_ERRNO_INVALID_CONV_START_TRIG_TYPE ;
goto VERIFY_ERROR ;
break ;
}
//Sample & Hold feature
if ( flags & ME_IO_STREAM_CONFIG_SAMPLE_AND_HOLD ) {
if ( instance - > sh ) {
ctrl | = ME4600_AI_CTRL_BIT_SAMPLE_HOLD ;
} else {
PERROR_CRITICAL ( " UNCHECK S&H feature! \n " ) ;
err = ME_ERRNO_INVALID_FLAGS ;
goto VERIFY_ERROR ;
}
}
//Enable IRQs sources but leave latches blocked.
ctrl | = ( ME4600_AI_CTRL_BIT_HF_IRQ | ME4600_AI_CTRL_BIT_SC_IRQ | ME4600_AI_CTRL_BIT_LE_IRQ ) ; //The last IRQ source (ME4600_AI_CTRL_BIT_LE_IRQ) is unused!
//Everything is good. Finalize
spin_lock_irqsave ( instance - > ctrl_reg_lock , cpu_flags ) ;
tmp = inl ( instance - > ctrl_reg ) ;
//Preserve EXT IRQ and OFFSET settings. Clean other bits.
tmp & =
( ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET |
ME4600_AI_CTRL_BIT_FULLSCALE | ME4600_AI_CTRL_BIT_OFFSET ) ;
// write the control word
outl ( ctrl | tmp , 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 | tmp ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
//Set the global parameters end exit.
instance - > chan_list_len = count ;
instance - > fifo_irq_threshold = fifo_irq_threshold ;
if ( trigger - > iAcqStopTrigType = = ME_TRIG_TYPE_COUNT ) {
data_required =
( unsigned long long ) trigger - > iAcqStopCount *
( unsigned long long ) count ;
if ( data_required > UINT_MAX )
data_required = UINT_MAX ;
instance - > data_required = ( unsigned int ) data_required ;
} else if ( trigger - > iScanStopTrigType = = ME_TRIG_TYPE_COUNT )
instance - > data_required =
( unsigned long long ) trigger - > iScanStopCount ;
else
instance - > data_required = 0 ;
// Mark subdevice as configured to work in stream mode.
instance - > status = ai_status_stream_configured ;
// Deinit single config. Set all entries to NOT_CONFIGURED.
for ( i = 0 ; i < instance - > channels ; i + + ) {
instance - > single_config [ i ] . status =
ME_SINGLE_CHANNEL_NOT_CONFIGURED ;
}
2009-03-16 17:45:13 +01:00
VERIFY_ERROR : // Error in code. Wrong setting check. This should never ever happend!
2008-11-01 00:39:12 +01:00
spin_unlock_irqrestore ( & instance - > subdevice_lock , cpu_flags ) ;
2009-03-16 17:45:13 +01:00
ERROR : // Error in settings.
2008-11-01 00:39:12 +01:00
ME_SUBDEVICE_EXIT ;
return err ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_new_values ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int time_out , int * count , int flags )
{
me4600_ai_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
unsigned long t ;
unsigned long j ;
int volatile head ;
PDEBUG ( " executed. idx=0 \n " ) ;
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( time_out < 0 ) {
PERROR ( " Invalid time_out specified. \n " ) ;
return ME_ERRNO_INVALID_TIMEOUT ;
}
if ( time_out ) {
t = ( time_out * HZ ) / 1000 ;
if ( t = = 0 )
t = 1 ;
} else { // Max time.
t = LONG_MAX ;
}
instance = ( me4600_ai_subdevice_t * ) subdevice ;
ME_SUBDEVICE_ENTER ;
j = jiffies ;
while ( 1 ) {
// Only runing device can generate break.
head = instance - > circ_buf . head ;
wait_event_interruptible_timeout ( instance - > wait_queue ,
( ( head ! =
instance - > circ_buf . head )
| |
( ( instance - > status < =
ai_status_stream_run_wait )
& & ( instance - > status > =
ai_status_stream_end_wait ) ) ) ,
t ) ;
if ( head ! = instance - > circ_buf . head ) { // New data in buffer.
break ;
} else if ( instance - > status = = ai_status_stream_end ) { // End of work.
break ;
} else if ( instance - > status = = ai_status_stream_fifo_error ) {
err = ME_ERRNO_FIFO_BUFFER_OVERFLOW ;
break ;
} else if ( instance - > status = = ai_status_stream_buffer_error ) {
err = ME_ERRNO_RING_BUFFER_OVERFLOW ;
break ;
} else if ( instance - > status = = ai_status_stream_error ) {
err = ME_ERRNO_INTERNAL ;
break ;
} else if ( ( jiffies - j ) > = t ) {
PERROR ( " Wait on values timed out. \n " ) ;
err = ME_ERRNO_TIMEOUT ;
break ;
} else if ( signal_pending ( current ) ) {
PERROR ( " Wait on values interrupted from signal. \n " ) ;
err = ME_ERRNO_SIGNAL ;
break ;
}
// Correct timeout.
t - = jiffies - j ;
}
* count = me_circ_buf_values ( & instance - > circ_buf ) ;
ME_SUBDEVICE_EXIT ;
return err ;
}
2009-03-16 17:45:13 +01:00
static inline int me4600_ai_io_stream_read_get_value ( me4600_ai_subdevice_t *
2008-11-01 00:39:12 +01:00
instance , int * values ,
const int count ,
const int flags )
{
int n ;
int i ;
uint32_t value ;
///Checking how many datas can be copied.
n = me_circ_buf_values ( & instance - > circ_buf ) ;
if ( n < = 0 )
return 0 ;
if ( n > count )
n = count ;
if ( flags & ME_IO_STREAM_READ_FRAMES ) {
if ( n < instance - > chan_list_len ) //Not enough data!
return 0 ;
n - = n % instance - > chan_list_len ;
}
for ( i = 0 ; i < n ; i + + ) {
value = * ( instance - > circ_buf . buf + instance - > circ_buf . tail ) ;
if ( put_user ( value , values + i ) ) {
PERROR ( " Cannot copy new values to user. \n " ) ;
return - ME_ERRNO_INTERNAL ;
}
instance - > circ_buf . tail + + ;
instance - > circ_buf . tail & = instance - > circ_buf . mask ;
}
return n ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_read ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int read_mode ,
int * values , int * count , int flags )
{
me4600_ai_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
int ret ;
int c = * count ;
int min = c ;
PDEBUG ( " executed. idx=0 \n " ) ;
if ( flags & ~ ME_IO_STREAM_READ_FRAMES ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
if ( ! values | | ! count ) {
PERROR ( " Request has invalid pointer. \n " ) ;
return ME_ERRNO_INVALID_POINTER ;
}
if ( c < 0 ) {
PERROR ( " Request has invalid value's counter. \n " ) ;
return ME_ERRNO_INVALID_VALUE_COUNT ;
}
if ( ( read_mode ! = ME_READ_MODE_BLOCKING )
& & ( read_mode ! = ME_READ_MODE_NONBLOCKING ) ) {
PERROR ( " Invalid read mode specified. \n " ) ;
return ME_ERRNO_INVALID_READ_MODE ;
}
if ( c = = 0 ) { //You get what you want! Nothing more or less.
return ME_ERRNO_SUCCESS ;
}
instance = ( me4600_ai_subdevice_t * ) subdevice ;
ME_SUBDEVICE_ENTER ;
//Check if subdevice is configured.
if ( instance - > chan_list_len < = 0 ) {
PERROR ( " Subdevice wasn't configured. \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_PREVIOUS_CONFIG ;
}
if ( flags & ME_IO_STREAM_READ_FRAMES ) {
if ( c < instance - > chan_list_len ) { //Not enough data requested.
PERROR
( " When using FRAME_READ mode minimal size is defined by channel list. \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_INVALID_VALUE_COUNT ;
}
}
if ( c > ( ME4600_AI_CIRC_BUF_COUNT - instance - > chan_list_len ) ) { // To return acceptable amount of data when user pass too big value.
min = ME4600_AI_CIRC_BUF_COUNT - instance - > chan_list_len ;
}
if ( flags & ME_IO_STREAM_READ_FRAMES ) {
//Wait for whole list.
if ( read_mode = = ME_READ_MODE_BLOCKING ) {
min = c - ( c % instance - > chan_list_len ) ;
}
if ( read_mode = = ME_READ_MODE_NONBLOCKING ) {
min = instance - > chan_list_len ;
}
}
if ( ( inl ( instance - > status_reg ) & ME4600_AI_STATUS_BIT_FSM ) ) { //Working
//If blocking mode -> wait for data.
if ( ( me_circ_buf_values ( & instance - > circ_buf ) < min )
& & ( read_mode = = ME_READ_MODE_BLOCKING ) ) {
wait_event_interruptible ( instance - > wait_queue ,
( ( me_circ_buf_values
( & instance - > circ_buf ) > = min )
| | ! ( inl ( instance - > status_reg )
&
ME4600_AI_STATUS_BIT_FSM ) ) ) ;
if ( signal_pending ( current ) ) {
PERROR
( " Wait on values interrupted from signal. \n " ) ;
err = ME_ERRNO_SIGNAL ;
}
}
}
ret = me4600_ai_io_stream_read_get_value ( instance , values , c , flags ) ;
if ( ret < 0 ) {
err = - ret ;
* count = 0 ;
} else if ( ret = = 0 ) {
* count = 0 ;
if ( instance - > status = = ai_status_stream_fifo_error ) {
err = ME_ERRNO_FIFO_BUFFER_OVERFLOW ;
instance - > status = ai_status_stream_end ;
} else if ( instance - > status = = ai_status_stream_buffer_error ) {
err = ME_ERRNO_RING_BUFFER_OVERFLOW ;
instance - > status = ai_status_stream_end ;
} else if ( instance - > status = = ai_status_stream_end ) {
err = ME_ERRNO_SUBDEVICE_NOT_RUNNING ;
} else if ( instance - > status = = ai_status_stream_error ) {
err = ME_ERRNO_INTERNAL ;
} else if ( instance - > status = = ai_status_none ) {
PDEBUG ( " Stream canceled. \n " ) ;
err = ME_ERRNO_INTERNAL ;
}
} else {
* count = ret ;
}
ME_SUBDEVICE_EXIT ;
return err ;
}
/** @brief Stop aqusation. Preserve FIFOs.
*
* @ param instance The subdevice instance ( pointer ) .
*/
2009-03-16 17:45:13 +01:00
static int ai_stop_immediately ( me4600_ai_subdevice_t * instance )
2008-11-01 00:39:12 +01:00
{
unsigned long cpu_flags = 0 ;
volatile uint32_t ctrl ;
const int timeout = HZ / 10 ; //100ms
int i ;
for ( i = 0 ; i < = timeout ; i + + ) {
spin_lock_irqsave ( instance - > ctrl_reg_lock , cpu_flags ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl & = ~ ME4600_AI_CTRL_BIT_STOP ;
ctrl | =
( ME4600_AI_CTRL_BIT_IMMEDIATE_STOP |
ME4600_AI_CTRL_BIT_HF_IRQ_RESET |
ME4600_AI_CTRL_BIT_SC_IRQ_RESET ) ;
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 - > ctrl_reg_lock , cpu_flags ) ;
if ( ! ( inl ( instance - > status_reg ) & ME4600_AI_STATUS_BIT_FSM ) ) { // Exit.
break ;
}
PINFO ( " Wait for stop: %d \n " , i + 1 ) ;
//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 ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_start ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int start_mode , int time_out , int flags )
{
me4600_ai_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
unsigned long cpu_flags = 0 ;
unsigned long ref ;
unsigned long delay = 0 ;
volatile uint32_t tmp ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
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 < 0 ) {
PERROR ( " Invalid timeout specified. \n " ) ;
return ME_ERRNO_INVALID_TIMEOUT ;
}
if ( time_out ) {
delay = ( time_out * HZ ) / 1000 ;
if ( delay = = 0 )
delay = 1 ;
}
ME_SUBDEVICE_ENTER
spin_lock_irqsave ( instance - > ctrl_reg_lock , cpu_flags ) ;
tmp = inl ( instance - > ctrl_reg ) ;
if ( ( tmp & ME4600_AI_STATUS_BIT_FSM ) ) {
PERROR ( " Conversion is already running. \n " ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
err = ME_ERRNO_SUBDEVICE_BUSY ;
goto ERROR ;
}
if ( instance - > chan_list_len = = 0 ) { //Not configured!
PERROR ( " Subdevice is not configured to work in stream mode! \n " ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
err = ME_ERRNO_PREVIOUS_CONFIG ;
goto ERROR ;
}
if ( ! ( tmp & ( ME4600_AI_CTRL_BIT_MODE_0 | ME4600_AI_CTRL_BIT_MODE_1 | ME4600_AI_CTRL_BIT_MODE_2 ) ) ) { //Mode 0 = single work => no stream config
PERROR ( " Subdevice is configured to work in single mode. \n " ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
err = ME_ERRNO_PREVIOUS_CONFIG ;
goto ERROR ;
}
//Reset stop bits.
tmp | = ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | ME4600_AI_CTRL_BIT_STOP ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
//Start datas' FIFO.
tmp | = ME4600_AI_CTRL_BIT_DATA_FIFO ;
//Free stop bits.
tmp & = ~ ( ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | ME4600_AI_CTRL_BIT_STOP ) ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
//Cancel control task
PDEBUG ( " Cancel control task. \n " ) ;
instance - > ai_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ai_control_task ) ;
//Set the starting values.
instance - > ISM . global_read = 0 ;
instance - > ISM . read = 0 ;
//Clear circular buffer
instance - > circ_buf . head = 0 ;
instance - > circ_buf . tail = 0 ;
//Set everything.
ai_data_acquisition_logic ( instance ) ;
//Set status to 'wait for start'
instance - > status = ai_status_stream_run_wait ;
// Set control task's timeout
instance - > timeout . delay = delay ;
instance - > timeout . start_time = jiffies ;
//Lets go! Start work
inl ( instance - > start_reg ) ;
PDEBUG_REG ( " start_reg inl(0x%lX+0x%lX) \n " , instance - > reg_base ,
instance - > start_reg - instance - > reg_base ) ;
// Schedule control task
instance - > ai_control_task_flag = 1 ;
queue_delayed_work ( instance - > me4600_workqueue ,
& instance - > ai_control_task , 1 ) ;
PDEVELOP ( " Delay:%ld \n " , delay ) ;
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 ! =
ai_status_stream_run_wait ) ,
( delay ) ? delay +
1 : LONG_MAX ) ;
if ( ( instance - > status ! = ai_status_stream_run )
& & ( instance - > status ! = ai_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 = ai_status_none ;
ai_stop_isr ( instance ) ;
err = ME_ERRNO_SIGNAL ;
} else if ( ( delay ) & & ( ( jiffies - ref ) > delay ) ) {
if ( instance - > status ! = ai_status_stream_run ) {
if ( instance - > status = = ai_status_stream_end ) {
PDEBUG ( " Timeout reached. \n " ) ;
} else if ( ( jiffies - ref ) > delay + 1 ) {
PERROR
( " Timeout reached. Not handled by control task! \n " ) ;
ai_stop_isr ( instance ) ;
instance - > status =
ai_status_stream_error ;
} else {
PERROR
( " Timeout reached. Signal come but status is strange: %d \n " ,
instance - > status ) ;
ai_stop_isr ( instance ) ;
instance - > status =
ai_status_stream_error ;
}
instance - > ai_control_task_flag = 0 ;
cancel_delayed_work ( & instance - > ai_control_task ) ;
err = ME_ERRNO_TIMEOUT ;
}
}
}
# ifdef MEDEBUG_INFO
tmp = inl ( instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg inl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
PINFO ( " STATUS_BIT_FSM=%s. \n " ,
( tmp & ME4600_AI_STATUS_BIT_FSM ) ? " on " : " off " ) ;
PINFO ( " CTRL_BIT_HF_IRQ=%s. \n " ,
( tmp & ME4600_AI_CTRL_BIT_HF_IRQ ) ? " enable " : " disable " ) ;
PINFO ( " CTRL_BIT_HF_IRQ_RESET=%s. \n " ,
( tmp & ME4600_AI_CTRL_BIT_HF_IRQ_RESET ) ? " reset " : " work " ) ;
PINFO ( " CTRL_BIT_SC_IRQ=%s. \n " ,
( tmp & ME4600_AI_CTRL_BIT_SC_IRQ ) ? " enable " : " disable " ) ;
PINFO ( " CTRL_BIT_SC_RELOAD=%s. \n " ,
( tmp & ME4600_AI_CTRL_BIT_SC_RELOAD ) ? " on " : " off " ) ;
PINFO ( " CTRL_BIT_SC_IRQ_RESET=%s. \n " ,
( tmp & ME4600_AI_CTRL_BIT_SC_IRQ_RESET ) ? " reset " : " work " ) ;
# endif
2009-03-16 17:45:13 +01:00
ERROR :
2008-11-01 00:39:12 +01:00
ME_SUBDEVICE_EXIT ;
return err ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_status ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int wait ,
int * status , int * values , int flags )
{
me4600_ai_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
if ( flags ) {
PERROR ( " Invalid flag specified. \n " ) ;
return ME_ERRNO_INVALID_FLAGS ;
}
ME_SUBDEVICE_ENTER ;
switch ( instance - > status ) {
case ai_status_single_configured :
case ai_status_stream_configured :
case ai_status_stream_end :
case ai_status_stream_fifo_error :
case ai_status_stream_buffer_error :
case ai_status_stream_error :
* status = ME_STATUS_IDLE ;
break ;
case ai_status_stream_run_wait :
case ai_status_stream_run :
case ai_status_stream_end_wait :
* status = ME_STATUS_BUSY ;
break ;
case ai_status_none :
default :
* status =
( inl ( instance - > status_reg ) & ME4600_AI_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 ! =
ai_status_stream_run_wait )
& & ( instance - > status ! =
ai_status_stream_run )
& & ( instance - > status ! =
ai_status_stream_end_wait ) ) ,
LONG_MAX ) ;
if ( instance - > status ! = ai_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 = ai_status_none ;
ai_stop_isr ( instance ) ;
err = ME_ERRNO_SIGNAL ;
}
* status = ME_STATUS_IDLE ;
}
* values = me_circ_buf_values ( & instance - > circ_buf ) ;
PDEBUG ( " me_circ_buf_values(&instance->circ_buf)=%d. \n " , * values ) ;
ME_SUBDEVICE_EXIT ;
return err ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_io_stream_stop ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
struct file * filep ,
int stop_mode , int flags )
{
/**
@ note Stop is implemented only in blocking mode .
@ note Function return when state machine is stoped .
*/
me4600_ai_subdevice_t * instance ;
unsigned long cpu_flags ;
uint32_t ctrl ;
int ret ;
PDEBUG ( " executed. idx=0 \n " ) ;
if ( flags ) {
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 ;
}
instance = ( me4600_ai_subdevice_t * ) subdevice ;
ME_SUBDEVICE_ENTER ;
// Mark as stopping. => Software stop.
instance - > status = ai_status_stream_end_wait ;
if ( stop_mode = = ME_STOP_MODE_IMMEDIATE ) {
ret = ai_stop_immediately ( instance ) ;
if ( ret ) {
PERROR ( " FSM is still busy. \n " ) ;
ME_SUBDEVICE_EXIT ;
return ME_ERRNO_SUBDEVICE_BUSY ;
}
instance - > ai_control_task_flag = 0 ;
} else if ( stop_mode = = ME_STOP_MODE_LAST_VALUE ) {
// Set stop bit in registry.
spin_lock_irqsave ( instance - > ctrl_reg_lock , cpu_flags ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | = ME4600_AI_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 ) ;
spin_unlock_irqrestore ( instance - > ctrl_reg_lock , cpu_flags ) ;
// Only runing process will interrupt this call. Events are signaled when status change.
wait_event_interruptible_timeout ( instance - > wait_queue ,
( instance - > status ! =
ai_status_stream_end_wait ) ,
LONG_MAX ) ;
if ( instance - > status ! = ai_status_stream_end ) {
PDEBUG ( " Stopping stream canceled. \n " ) ;
ret = ME_ERRNO_CANCELLED ;
}
if ( signal_pending ( current ) ) {
PERROR ( " Stopping stream interrupted. \n " ) ;
instance - > status = ai_status_none ;
ret = ME_ERRNO_SIGNAL ;
}
// End of work.
ai_stop_immediately ( instance ) ;
}
ret = ai_read_data_pooling ( instance ) ;
if ( ret > 0 ) { // Everything fine. More datas put to software buffer.
instance - > status = ai_status_stream_end ;
ret = ME_ERRNO_SUCCESS ;
// Signal that we put last data to software buffer.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
} else if ( ret = = 0 ) { // Everything fine. No more datas in FIFO.
instance - > status = ai_status_stream_end ;
ret = ME_ERRNO_SUCCESS ;
} else if ( ret = = - ME_ERRNO_RING_BUFFER_OVERFLOW ) { // Stop is unsuccessful, buffer is overflow.
instance - > status = ai_status_stream_buffer_error ;
ret = ME_ERRNO_SUCCESS ;
} else { // Stop is unsuccessful
instance - > status = ai_status_stream_end ;
ret = - ret ;
}
ME_SUBDEVICE_EXIT ;
return ret ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_range_by_min_max ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int unit ,
int * min ,
int * max , int * maxdata , int * range )
{
me4600_ai_subdevice_t * instance ;
int i ;
int r = - 1 ;
int diff = 21E6 ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
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 ) ) {
for ( i = 0 ; i < instance - > ranges_len ; i + + ) {
if ( ( instance - > ranges [ i ] . min < = * min )
& & ( ( instance - > ranges [ i ] . max + 1000 ) > = * max ) ) {
if ( ( instance - > ranges [ i ] . max -
instance - > ranges [ i ] . min ) - ( * max - * min ) <
diff ) {
r = i ;
diff =
( instance - > ranges [ i ] . max -
instance - > ranges [ i ] . min ) - ( * max -
* min ) ;
}
}
}
if ( r < 0 ) {
PERROR ( " No matching range found. \n " ) ;
return ME_ERRNO_NO_RANGE ;
} else {
* min = instance - > ranges [ r ] . min ;
* max = instance - > ranges [ r ] . max ;
* maxdata = ME4600_AI_MAX_DATA ;
* range = r ;
}
} else {
PERROR ( " Invalid physical unit specified. \n " ) ;
return ME_ERRNO_INVALID_UNIT ;
}
return ME_ERRNO_SUCCESS ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_number_ranges ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int unit , int * count )
{
me4600_ai_subdevice_t * instance ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
if ( ( unit = = ME_UNIT_VOLT ) | | ( unit = = ME_UNIT_ANY ) ) {
* count = instance - > ranges_len ;
} else {
* count = 0 ;
}
return ME_ERRNO_SUCCESS ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_range_info ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int range ,
int * unit ,
int * min , int * max , int * maxdata )
{
me4600_ai_subdevice_t * instance ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
if ( ( range < instance - > ranges_len ) & & ( range > = 0 ) ) {
* unit = ME_UNIT_VOLT ;
* min = instance - > ranges [ range ] . min ;
* max = instance - > ranges [ range ] . max ;
* maxdata = ME4600_AI_MAX_DATA ;
} else {
PERROR ( " Invalid range number specified. \n " ) ;
return ME_ERRNO_INVALID_RANGE ;
}
return ME_ERRNO_SUCCESS ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_timer ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int timer ,
int * base_frequency ,
long long * min_ticks , long long * max_ticks )
{
me4600_ai_subdevice_t * instance ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
switch ( timer ) {
case ME_TIMER_ACQ_START :
* base_frequency = ME4600_AI_BASE_FREQUENCY ;
* min_ticks = ME4600_AI_MIN_ACQ_TICKS ;
* max_ticks = ME4600_AI_MAX_ACQ_TICKS ;
break ;
case ME_TIMER_SCAN_START :
* base_frequency = ME4600_AI_BASE_FREQUENCY ;
* min_ticks = ME4600_AI_MIN_SCAN_TICKS ;
* max_ticks = ME4600_AI_MAX_SCAN_TICKS ;
break ;
case ME_TIMER_CONV_START :
* base_frequency = ME4600_AI_BASE_FREQUENCY ;
* min_ticks = ME4600_AI_MIN_CHAN_TICKS ;
* max_ticks = ME4600_AI_MAX_CHAN_TICKS ;
break ;
default :
PERROR ( " Invalid timer specified.(0x%04x) \n " , timer ) ;
return ME_ERRNO_INVALID_TIMER ;
}
return ME_ERRNO_SUCCESS ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_number_channels ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int * number )
{
me4600_ai_subdevice_t * instance ;
PDEBUG ( " executed. idx=0 \n " ) ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
* number = instance - > channels ;
return ME_ERRNO_SUCCESS ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_subdevice_type ( me_subdevice_t * subdevice ,
2008-11-01 00:39:12 +01:00
int * type , int * subtype )
{
PDEBUG ( " executed. idx=0 \n " ) ;
* type = ME_TYPE_AI ;
* subtype = ME_SUBTYPE_STREAMING ;
return ME_ERRNO_SUCCESS ;
}
2009-03-16 17:45:13 +01:00
static int me4600_ai_query_subdevice_caps ( me_subdevice_t * subdevice , int * caps )
2008-11-01 00:39:12 +01:00
{
PDEBUG ( " executed. idx=0 \n " ) ;
* caps =
ME_CAPS_AI_TRIG_SYNCHRONOUS | ME_CAPS_AI_FIFO |
ME_CAPS_AI_FIFO_THRESHOLD ;
return ME_ERRNO_SUCCESS ;
}
static int me4600_ai_query_subdevice_caps_args ( struct me_subdevice * subdevice ,
int cap , int * args , int count )
{
me4600_ai_subdevice_t * instance ;
int err = ME_ERRNO_SUCCESS ;
instance = ( me4600_ai_subdevice_t * ) subdevice ;
PDEBUG ( " executed. idx=0 \n " ) ;
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 ] = ME4600_AI_FIFO_COUNT ;
break ;
case ME_CAP_AI_BUFFER_SIZE :
args [ 0 ] =
( instance - > circ_buf . buf ) ? ME4600_AI_CIRC_BUF_COUNT : 0 ;
break ;
default :
PERROR ( " Invalid capability. \n " ) ;
err = ME_ERRNO_INVALID_CAP ;
args [ 0 ] = 0 ;
}
return err ;
}
2009-03-16 17:45:13 +01:00
void ai_limited_isr ( me4600_ai_subdevice_t * instance , const uint32_t irq_status ,
2008-11-01 00:39:12 +01:00
const uint32_t ctrl_status )
{
int to_read ;
if ( ! instance - > fifo_irq_threshold ) { //No threshold provided. SC ends work. HF need reseting.
if ( irq_status & ME4600_IRQ_STATUS_BIT_SC ) {
if ( ai_read_data ( instance , instance - > ISM . next ) ! = instance - > ISM . next ) { //ERROR!
PERROR
( " Limited amounts aqusition with TH=0: Circular buffer full! \n " ) ;
instance - > status =
ai_status_stream_buffer_error ;
} else {
instance - > status = ai_status_stream_end ;
}
//End of work.
ai_stop_isr ( instance ) ;
} else if ( irq_status & ME4600_IRQ_STATUS_BIT_AI_HF ) {
instance - > ISM . global_read + = ME4600_AI_FIFO_HALF ;
if ( ai_read_data ( instance , ME4600_AI_FIFO_HALF ) ! = ME4600_AI_FIFO_HALF ) { //ERROR!
PERROR
( " Limited amounts aqusition with TH = 0: Circular buffer full! \n " ) ;
//End of work.
ai_stop_isr ( instance ) ;
instance - > status =
ai_status_stream_buffer_error ;
} else {
//Continue.
ai_limited_ISM ( instance , irq_status ) ;
}
}
//Signal user.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
} else //if(instance->fifo_irq_threshold)
{
if ( irq_status & ME4600_IRQ_STATUS_BIT_SC ) {
instance - > ISM . read = 0 ;
if ( ( instance - > fifo_irq_threshold < ME4600_AI_FIFO_HALF )
& & ( ! ( ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA ) ) )
{
to_read =
ME4600_AI_FIFO_HALF -
( ME4600_AI_FIFO_HALF %
instance - > fifo_irq_threshold ) ;
PDEBUG
( " Limited amounts aqusition with TH != 0: Not fast enough data aqusition! correction=%d \n " ,
to_read ) ;
} else {
to_read = instance - > ISM . next ;
}
instance - > ISM . global_read + = to_read ;
ai_reschedule_SC ( instance ) ;
if ( ai_read_data ( instance , to_read ) ! = to_read ) { //ERROR!
PERROR
( " Limited amounts aqusition with TH != 0: Circular buffer full! \n " ) ;
//End of work.
ai_stop_isr ( instance ) ;
instance - > status =
ai_status_stream_buffer_error ;
} else {
//Continue.
ai_limited_ISM ( instance , irq_status ) ;
}
//Signal user.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
} else if ( irq_status & ME4600_IRQ_STATUS_BIT_AI_HF ) {
instance - > ISM . read + = ME4600_AI_FIFO_HALF ;
instance - > ISM . global_read + = ME4600_AI_FIFO_HALF ;
if ( ai_read_data ( instance , ME4600_AI_FIFO_HALF ) ! = ME4600_AI_FIFO_HALF ) { //ERROR!
PERROR
( " Limited amounts aqusition with TH != 0: Circular buffer full! \n " ) ;
ai_stop_isr ( instance ) ;
instance - > status =
ai_status_stream_buffer_error ;
//Signal user.
wake_up_interruptible_all ( & instance - >
wait_queue ) ;
} else {
//Countinue.
ai_limited_ISM ( instance , irq_status ) ;
}
}
if ( instance - > ISM . global_read > = instance - > data_required ) { //End of work. Next paranoid pice of code: '>=' instead od '==' only to be sure.
ai_stop_isr ( instance ) ;
if ( instance - > status < ai_status_stream_end ) {
instance - > status = ai_status_stream_end ;
}
# ifdef MEDEBUG_ERROR
if ( instance - > ISM . global_read > instance - > data_required ) { //This is security check case. This should never ever happend!
PERROR
( " Limited amounts aqusition: Read more data than necessary! data_required=%d < read=%d \n " ,
instance - > data_required ,
instance - > ISM . global_read ) ;
//Signal error (warning??).
instance - > status = ai_status_stream_error ;
}
# endif
}
}
}
2009-03-16 17:45:13 +01:00
void ai_infinite_isr ( me4600_ai_subdevice_t * instance ,
2008-11-01 00:39:12 +01:00
const uint32_t irq_status , const uint32_t ctrl_status )
{
int to_read ;
if ( irq_status & ME4600_IRQ_STATUS_BIT_SC ) { //next chunck of data -> read fifo
//Set new state in ISM.
if ( ( instance - > fifo_irq_threshold < ME4600_AI_FIFO_HALF ) & & ( ! ( ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA ) ) ) { //There is more data than we ecpected. Propably we aren't fast enough. Read as many as possible.
if ( instance - > fifo_irq_threshold ) {
to_read =
ME4600_AI_FIFO_HALF -
( ME4600_AI_FIFO_HALF %
instance - > fifo_irq_threshold ) ;
if ( to_read > instance - > fifo_irq_threshold ) {
PDEBUG
( " Infinite aqusition: Not fast enough data aqusition! TH != 0: correction=%d \n " ,
to_read ) ;
}
} else { //No threshold specified.
to_read = ME4600_AI_FIFO_HALF ;
}
} else {
to_read = instance - > ISM . next ;
}
instance - > ISM . read + = to_read ;
//Get data
if ( ai_read_data ( instance , to_read ) ! = to_read ) { //ERROR!
PERROR ( " Infinite aqusition: Circular buffer full! \n " ) ;
ai_stop_isr ( instance ) ;
instance - > status = ai_status_stream_buffer_error ;
} else {
ai_infinite_ISM ( instance ) ;
instance - > ISM . global_read + = instance - > ISM . read ;
instance - > ISM . read = 0 ;
}
//Signal data to user
wake_up_interruptible_all ( & instance - > wait_queue ) ;
} else if ( irq_status & ME4600_IRQ_STATUS_BIT_AI_HF ) { //fifo is half full -> read fifo Large blocks only!
instance - > ISM . read + = ME4600_AI_FIFO_HALF ;
if ( ai_read_data ( instance , ME4600_AI_FIFO_HALF ) ! = ME4600_AI_FIFO_HALF ) { //ERROR!
PERROR ( " Infinite aqusition: Circular buffer full! \n " ) ;
ai_stop_isr ( instance ) ;
instance - > status = ai_status_stream_buffer_error ;
//Signal it.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
} else {
ai_infinite_ISM ( instance ) ;
}
}
}
static irqreturn_t me4600_ai_isr ( int irq , void * dev_id )
{ /// @note This is time critical function!
uint32_t irq_status ;
uint32_t ctrl_status ;
me4600_ai_subdevice_t * instance = dev_id ;
//int to_read;
PDEBUG ( " executed. idx=0 \n " ) ;
if ( irq ! = instance - > irq ) {
PERROR ( " Incorrect interrupt num: %d. \n " , irq ) ;
return IRQ_NONE ;
}
irq_status = inl ( instance - > irq_status_reg ) ;
if ( !
( irq_status &
( ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC ) ) ) {
# ifdef MEDEBUG_INFO
if ( ( irq_status & ( ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC | ME4600_IRQ_STATUS_BIT_LE ) ) = = ME4600_IRQ_STATUS_BIT_LE ) { //This is security check case. LE is unused. This should never ever happend.
PINFO
( " %ld Shared interrupt. %s(): irq_status_reg=LE_IRQ \n " ,
2009-01-07 23:31:57 +01:00
jiffies , __func__ ) ;
2008-11-01 00:39:12 +01:00
} else {
PINFO
( " %ld Shared interrupt. %s(): irq_status_reg=0x%04X \n " ,
2009-01-07 23:31:57 +01:00
jiffies , __func__ , irq_status ) ;
2008-11-01 00:39:12 +01:00
}
# endif
return IRQ_NONE ;
}
if ( ! instance - > circ_buf . buf ) { //Security check.
PERROR_CRITICAL ( " CIRCULAR BUFFER NOT EXISTS! \n " ) ;
ai_stop_isr ( instance ) ;
return IRQ_HANDLED ;
}
//Get the status register.
ctrl_status = inl ( instance - > status_reg ) ;
# ifdef MEDEBUG_INFO
if ( irq_status & ME4600_IRQ_STATUS_BIT_AI_HF )
PINFO ( " HF interrupt active \n " ) ;
if ( irq_status & ME4600_IRQ_STATUS_BIT_SC )
PINFO ( " SC interrupt active \n " ) ;
if ( irq_status & ME4600_IRQ_STATUS_BIT_LE )
PINFO ( " LE interrupt active \n " ) ;
# endif
//This is safety check!
if ( ( irq_status & ME4600_IRQ_STATUS_BIT_AI_HF )
& & ( ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA ) ) {
PDEBUG ( " HF interrupt active but FIFO under half \n " ) ;
//Reset HF interrupt latch.
spin_lock ( instance - > ctrl_reg_lock ) ;
outl ( ctrl_status | ME4600_AI_CTRL_BIT_HF_IRQ_RESET ,
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_status ) ;
outl ( ctrl_status , 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_status ) ;
spin_unlock ( instance - > ctrl_reg_lock ) ;
return IRQ_HANDLED ;
}
# ifdef MEDEBUG_INFO
PINFO ( " STATUS_BIT_FSM=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_FSM ) ? " on " : " off " ) ;
PINFO ( " STATUS_BIT_EF_CHANNEL=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_EF_CHANNEL ) ? " not empty " :
" empty " ) ;
PINFO ( " STATUS_BIT_HF_CHANNEL=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_HF_CHANNEL ) ? " < HF " :
" > HF " ) ;
PINFO ( " STATUS_BIT_FF_CHANNEL=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_FF_CHANNEL ) ? " not full " :
" full " ) ;
PINFO ( " STATUS_BIT_EF_DATA=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_EF_DATA ) ? " not empty " :
" empty " ) ;
PINFO ( " STATUS_BIT_HF_DATA=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA ) ? " < HF " : " > HF " ) ;
PINFO ( " STATUS_BIT_FF_DATA=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_FF_DATA ) ? " not full " :
" full " ) ;
PINFO ( " CTRL_BIT_HF_IRQ=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_HF_IRQ ) ? " enable " : " disable " ) ;
PINFO ( " CTRL_BIT_HF_IRQ_RESET=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_HF_IRQ_RESET ) ? " reset " :
" work " ) ;
PINFO ( " CTRL_BIT_SC_IRQ=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_SC_IRQ ) ? " enable " : " disable " ) ;
PINFO ( " CTRL_BIT_SC_RELOAD=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_SC_RELOAD ) ? " on " : " off " ) ;
PINFO ( " CTRL_BIT_SC_IRQ_RESET=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_SC_IRQ_RESET ) ? " reset " :
" work " ) ;
# endif
//Look for overflow error.
if ( ! ( ctrl_status & ME4600_AI_STATUS_BIT_FF_DATA ) ) {
//FIFO is full. Read datas and reset all settings.
PERROR ( " FIFO overflow. \n " ) ;
ai_read_data ( instance , ME4600_AI_FIFO_COUNT ) ;
ai_stop_isr ( instance ) ;
instance - > status = ai_status_stream_fifo_error ;
//Signal it.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
return IRQ_HANDLED ;
}
if ( ! instance - > data_required ) { //This is infinite aqusition.
# ifdef MEDEBUG_ERROR
if ( ( irq_status &
( ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC ) )
= =
( ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC ) ) {
///In infinite mode only one interrupt source should be reported!
PERROR
( " Error in ISM! Infinite aqusition: HF and SC interrupts active! threshold=%d next=%d ctrl=0x%04X irq_status_reg=0x%04X " ,
instance - > fifo_irq_threshold , instance - > ISM . next ,
ctrl_status , irq_status ) ;
}
# endif
ai_infinite_isr ( instance , irq_status , ctrl_status ) ;
# ifdef MEDEBUG_INFO
ctrl_status = inl ( instance - > ctrl_reg ) ;
# endif
} else {
ai_limited_isr ( instance , irq_status , ctrl_status ) ;
ctrl_status = inl ( instance - > status_reg ) ;
if ( ! ( ctrl_status & ( ME4600_AI_STATUS_BIT_HF_DATA | ME4600_AI_CTRL_BIT_HF_IRQ_RESET ) ) ) { //HF active, but we have more than half already => HF will never come
PDEBUG
( " MISSED HF. data_required=%d ISM.read=%d ISM.global=%d ISM.next=%d \n " ,
instance - > data_required , instance - > ISM . read ,
instance - > ISM . global_read , instance - > ISM . next ) ;
ai_limited_isr ( instance , ME4600_IRQ_STATUS_BIT_AI_HF ,
ctrl_status ) ;
}
}
# ifdef MEDEBUG_INFO
PINFO ( " STATUS_BIT_FSM=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_FSM ) ? " on " : " off " ) ;
PINFO ( " STATUS_BIT_EF_CHANNEL=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_EF_CHANNEL ) ? " not empty " :
" empty " ) ;
PINFO ( " STATUS_BIT_HF_CHANNEL=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_HF_CHANNEL ) ? " < HF " :
" > HF " ) ;
PINFO ( " STATUS_BIT_FF_CHANNEL=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_FF_CHANNEL ) ? " not full " :
" full " ) ;
PINFO ( " STATUS_BIT_EF_DATA=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_EF_DATA ) ? " not empty " :
" empty " ) ;
PINFO ( " STATUS_BIT_HF_DATA=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_HF_DATA ) ? " < HF " : " > HF " ) ;
PINFO ( " STATUS_BIT_FF_DATA=%s. \n " ,
( ctrl_status & ME4600_AI_STATUS_BIT_FF_DATA ) ? " not full " :
" full " ) ;
PINFO ( " CTRL_BIT_HF_IRQ_RESET=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_HF_IRQ_RESET ) ? " reset " :
" work " ) ;
PINFO ( " CTRL_BIT_SC_IRQ=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_SC_IRQ ) ? " enable " : " disable " ) ;
PINFO ( " CTRL_BIT_SC_RELOAD=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_SC_RELOAD ) ? " on " : " off " ) ;
PINFO ( " CTRL_BIT_SC_IRQ_RESET=%s. \n " ,
( ctrl_status & ME4600_AI_CTRL_BIT_SC_IRQ_RESET ) ? " reset " :
" work " ) ;
PINFO ( " %ld END \n " , jiffies ) ;
# endif
return IRQ_HANDLED ;
}
/** @brief Stop aqusation of data. Reset interrupts' laches. Clear data's FIFO.
*
* @ param instance The subdevice instance ( pointer ) .
*/
2009-03-16 17:45:13 +01:00
inline void ai_stop_isr ( me4600_ai_subdevice_t * instance )
2008-11-01 00:39:12 +01:00
{ /// @note This is soft time critical function!
register uint32_t tmp ;
spin_lock ( instance - > ctrl_reg_lock ) ;
//Stop all. Reset interrupt laches. Reset data FIFO.
tmp = inl ( instance - > ctrl_reg ) ;
tmp | =
( ME4600_AI_CTRL_BIT_IMMEDIATE_STOP | ME4600_AI_CTRL_BIT_HF_IRQ_RESET
| ME4600_AI_CTRL_BIT_LE_IRQ_RESET |
ME4600_AI_CTRL_BIT_SC_IRQ_RESET ) ;
tmp & = ~ ME4600_AI_CTRL_BIT_DATA_FIFO ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
spin_unlock ( instance - > ctrl_reg_lock ) ;
}
/** @brief Copy data from fifo to circular buffer.
*
* @ param instance The subdevice instance ( pointer ) .
* @ param count The number of requested data .
*
* @ return On success : Number of copied values .
* @ return On error : - ME_ERRNO_RING_BUFFER_OVERFLOW .
*/
2009-03-16 17:45:13 +01:00
static inline int ai_read_data ( me4600_ai_subdevice_t * instance ,
2008-11-01 00:39:12 +01:00
const int count )
{ /// @note This is time critical function!
int c = count ;
int empty_space ;
int copied = 0 ;
int i , j ;
empty_space = me_circ_buf_space_to_end ( & instance - > circ_buf ) ;
if ( empty_space < = 0 ) {
PDEBUG ( " Circular buffer full. \n " ) ;
return - ME_ERRNO_RING_BUFFER_OVERFLOW ;
}
if ( empty_space < c ) { //Copy first part. Max to end of buffer.
PDEBUG
( " Try to copy %d values from FIFO to circular buffer (pass 1). \n " ,
empty_space ) ;
for ( i = 0 ; i < empty_space ; i + + ) {
* ( instance - > circ_buf . buf + instance - > circ_buf . head ) =
( inw ( instance - > data_reg ) ^ 0x8000 ) ;
instance - > circ_buf . head + + ;
}
instance - > circ_buf . head & = instance - > circ_buf . mask ;
c - = empty_space ;
copied = empty_space ;
empty_space = me_circ_buf_space_to_end ( & instance - > circ_buf ) ;
}
if ( empty_space > 0 ) {
j = ( empty_space < c ) ? empty_space : c ;
PDEBUG
( " Try to copy %d values from FIFO to circular buffer (pass 2). \n " ,
c ) ;
for ( i = 0 ; i < j ; i + + ) {
* ( instance - > circ_buf . buf + instance - > circ_buf . head ) =
( inw ( instance - > data_reg ) ^ 0x8000 ) ;
instance - > circ_buf . head + + ;
}
instance - > circ_buf . head & = instance - > circ_buf . mask ;
copied + = j ;
}
return copied ;
}
2009-03-16 17:45:13 +01:00
inline void ai_infinite_ISM ( me4600_ai_subdevice_t * instance )
2008-11-01 00:39:12 +01:00
{ /// @note This is time critical function!
register volatile uint32_t ctrl_set , ctrl_reset , tmp ;
if ( instance - > fifo_irq_threshold < ME4600_AI_FIFO_MAX_SC ) { // Only sample counter with reloadnig is working. Reset it.
PINFO
( " Only sample counter with reloadnig is working. Reset it. \n " ) ;
ctrl_set = ME4600_AI_CTRL_BIT_SC_IRQ_RESET ;
ctrl_reset = ~ ME4600_AI_CTRL_BIT_SC_IRQ_RESET ;
} else if ( instance - > fifo_irq_threshold = = instance - > ISM . read ) { //This is SC interrupt for large block. The whole section is done. Reset SC_IRQ an HF_IRQ and start everything again from beginning.
PINFO
( " This is SC interrupt for large block. The whole section is done. Reset SC_IRQ an HF_IRQ and start everything again from beginning. \n " ) ;
ctrl_set =
ME4600_AI_CTRL_BIT_SC_IRQ_RESET |
ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
ctrl_reset =
~ ( ME4600_AI_CTRL_BIT_SC_IRQ_RESET |
ME4600_AI_CTRL_BIT_HF_IRQ_RESET ) ;
} else if ( instance - > fifo_irq_threshold > = ( ME4600_AI_FIFO_MAX_SC + instance - > ISM . read ) ) { //This is HF interrupt for large block.The next interrupt should be from HF, also. Reset HF.
PINFO
( " This is HF interrupt for large block.The next interrupt should be from HF, also. Reset HF. \n " ) ;
ctrl_set = ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
ctrl_reset = ~ ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
} else { //This is HF interrupt for large block.The next interrupt should be from SC. Don't reset HF!
PINFO
( " This is HF interrupt for large block.The next interrupt should be from SC. Don't reset HF! \n " ) ;
ctrl_set = ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
ctrl_reset = 0xFFFFFFFF ;
}
//Reset interrupt latch.
spin_lock ( instance - > ctrl_reg_lock ) ;
tmp = inl ( instance - > ctrl_reg ) ;
PINFO ( " ctrl=0x%x ctrl_set=0x%x ctrl_reset=0x%x \n " , tmp , ctrl_set ,
ctrl_reset ) ;
tmp | = ctrl_set ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
if ( ctrl_reset ! = 0xFFFFFFFF ) {
outl ( tmp & ctrl_reset , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reset outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
tmp & ctrl_reset ) ;
}
spin_unlock ( instance - > ctrl_reg_lock ) ;
}
2009-03-16 17:45:13 +01:00
inline void ai_limited_ISM ( me4600_ai_subdevice_t * instance ,
2008-11-01 00:39:12 +01:00
uint32_t irq_status )
{ /// @note This is time critical function!
register volatile uint32_t ctrl_set , ctrl_reset = 0xFFFFFFFF , tmp ;
if ( ! instance - > fifo_irq_threshold ) { //No threshold provided. SC ends work.
PINFO ( " No threshold provided. SC ends work. \n " ) ;
ctrl_set = ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
if ( instance - > data_required > ( ME4600_AI_FIFO_COUNT - 1 + instance - > ISM . global_read ) ) { //HF need reseting.
ctrl_reset & = ~ ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
}
} else //if(instance->fifo_irq_threshold)
{
if ( irq_status & ME4600_IRQ_STATUS_BIT_AI_HF ) {
PINFO ( " Threshold provided. Clear HF latch. \n " ) ;
ctrl_set = ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
if ( instance - > fifo_irq_threshold > = ( ME4600_AI_FIFO_MAX_SC + instance - > ISM . read ) ) { //This is not the last one. HF need reseting.
PINFO
( " The next interrupt is HF. HF need be activating. \n " ) ;
ctrl_reset = ~ ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
}
}
if ( irq_status & ME4600_IRQ_STATUS_BIT_SC ) {
PINFO ( " Threshold provided. Restart SC. \n " ) ;
ctrl_set = ME4600_AI_CTRL_BIT_SC_IRQ_RESET ;
ctrl_reset & = ~ ME4600_AI_CTRL_BIT_SC_IRQ_RESET ;
if ( instance - > fifo_irq_threshold > = ME4600_AI_FIFO_MAX_SC ) { //This is not the last one. HF need to be activating.
PINFO
( " The next interrupt is HF. HF need to be activating. \n " ) ;
ctrl_reset & = ~ ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
}
}
}
//Reset interrupt latch.
spin_lock ( instance - > ctrl_reg_lock ) ;
tmp = inl ( instance - > ctrl_reg ) ;
tmp | = ctrl_set ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
if ( ctrl_reset ! = 0xFFFFFFFF ) {
outl ( tmp & ctrl_reset , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
tmp & ctrl_reset ) ;
}
spin_unlock ( instance - > ctrl_reg_lock ) ;
}
/** @brief Last chunck of datas. We must reschedule sample counter.
* @ note Last chunck .
* Leaving SC_RELOAD doesn ' t do any harm , but in some bad case can make extra interrupts .
* @ warning When threshold is wrongly set some IRQ are lost . ( ! ! ! )
*/
2009-03-16 17:45:13 +01:00
inline void ai_reschedule_SC ( me4600_ai_subdevice_t * instance )
2008-11-01 00:39:12 +01:00
{
register uint32_t rest ;
if ( instance - > data_required < = instance - > ISM . global_read )
return ;
rest = instance - > data_required - instance - > ISM . global_read ;
if ( rest < instance - > fifo_irq_threshold ) { //End of work soon ....
PDEBUG ( " Rescheduling SC from %d to %d. \n " ,
instance - > fifo_irq_threshold , rest ) ;
/// @note Write new value to SC <== DANGER! This is not safe solution! We can miss some inputs.
outl ( rest , instance - > sample_counter_reg ) ;
PDEBUG_REG ( " sample_counter_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > sample_counter_reg - instance - > reg_base ,
rest ) ;
instance - > fifo_irq_threshold = rest ;
if ( rest < ME4600_AI_FIFO_MAX_SC ) {
instance - > ISM . next = rest ;
} else {
instance - > ISM . next = rest % ME4600_AI_FIFO_HALF ;
if ( instance - > ISM . next + ME4600_AI_FIFO_HALF <
ME4600_AI_FIFO_MAX_SC ) {
instance - > ISM . next + = ME4600_AI_FIFO_HALF ;
}
}
}
}
/** Start the ISM. All must be reseted before enter to this function. */
2009-03-16 17:45:13 +01:00
inline void ai_data_acquisition_logic ( me4600_ai_subdevice_t * instance )
2008-11-01 00:39:12 +01:00
{
register uint32_t tmp ;
if ( ! instance - > data_required ) { //This is infinite aqusition.
if ( ! instance - > fifo_irq_threshold ) { //No threshold provided. Set SC to 0.5*FIFO. Clear the SC's latch.
//Set the sample counter
outl ( ME4600_AI_FIFO_HALF , instance - > sample_counter_reg ) ;
PDEBUG_REG
( " sample_counter_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > sample_counter_reg - instance - > reg_base ,
ME4600_AI_FIFO_HALF ) ;
} else { //Threshold provided. Set SC to treshold. Clear the SC's latch.
//Set the sample counter
outl ( instance - > fifo_irq_threshold ,
instance - > sample_counter_reg ) ;
PDEBUG_REG
( " sample_counter_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > sample_counter_reg - instance - > reg_base ,
instance - > fifo_irq_threshold ) ;
}
if ( instance - > fifo_irq_threshold < ME4600_AI_FIFO_MAX_SC ) { //Enable only sample counter's interrupt. Set reload bit. Clear the SC's latch.
spin_lock ( instance - > ctrl_reg_lock ) ;
tmp = inl ( instance - > ctrl_reg ) ;
tmp | = ME4600_AI_CTRL_BIT_SC_RELOAD ;
tmp & = ~ ME4600_AI_CTRL_BIT_SC_IRQ_RESET ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
tmp ) ;
spin_unlock ( instance - > ctrl_reg_lock ) ;
if ( ! instance - > fifo_irq_threshold ) { //No threshold provided. Set ISM.next to 0.5*FIFO.
instance - > ISM . next = ME4600_AI_FIFO_HALF ;
} else { //Threshold provided. Set ISM.next to treshold.
instance - > ISM . next =
instance - > fifo_irq_threshold ;
}
} else { //Enable sample counter's and HF's interrupts.
spin_lock ( instance - > ctrl_reg_lock ) ;
tmp = inl ( instance - > ctrl_reg ) ;
tmp | = ME4600_AI_CTRL_BIT_SC_RELOAD ;
tmp & =
~ ( ME4600_AI_CTRL_BIT_SC_IRQ_RESET |
ME4600_AI_CTRL_BIT_HF_IRQ_RESET ) ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
tmp ) ;
spin_unlock ( instance - > ctrl_reg_lock ) ;
instance - > ISM . next =
instance - > fifo_irq_threshold % ME4600_AI_FIFO_HALF ;
if ( instance - > ISM . next + ME4600_AI_FIFO_HALF <
ME4600_AI_FIFO_MAX_SC ) {
instance - > ISM . next + = ME4600_AI_FIFO_HALF ;
}
}
} else { //This aqusition is limited to set number of data.
if ( instance - > fifo_irq_threshold > = instance - > data_required ) { //Stupid situation.
instance - > fifo_irq_threshold = 0 ;
PDEBUG
( " Stupid situation: data_required(%d) < threshold(%d). \n " ,
instance - > fifo_irq_threshold ,
instance - > data_required ) ;
}
if ( ! instance - > fifo_irq_threshold ) { //No threshold provided. Easy case: HF=read and SC=end.
//Set the sample counter to data_required.
outl ( instance - > data_required ,
instance - > sample_counter_reg ) ;
PDEBUG_REG
( " sample_counter_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > sample_counter_reg - instance - > reg_base ,
instance - > data_required ) ;
//Reset the latches of sample counter and HF (if SC>FIFO).
//No SC reload!
spin_lock ( instance - > ctrl_reg_lock ) ;
tmp = inl ( instance - > ctrl_reg ) ;
tmp & =
~ ( ME4600_AI_CTRL_BIT_SC_IRQ_RESET |
ME4600_AI_CTRL_BIT_SC_RELOAD ) ;
if ( instance - > data_required >
( ME4600_AI_FIFO_COUNT - 1 ) ) {
tmp & = ~ ME4600_AI_CTRL_BIT_HF_IRQ_RESET ;
instance - > ISM . next =
instance - > data_required %
ME4600_AI_FIFO_HALF ;
instance - > ISM . next + = ME4600_AI_FIFO_HALF ;
} else {
instance - > ISM . next = instance - > data_required ;
}
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
tmp ) ;
spin_unlock ( instance - > ctrl_reg_lock ) ;
} else { //The most general case. We have concret numbe of required data and threshold. SC=TH
//Set the sample counter to threshold.
outl ( instance - > fifo_irq_threshold ,
instance - > sample_counter_reg ) ;
PDEBUG_REG
( " sample_counter_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > sample_counter_reg - instance - > reg_base ,
instance - > fifo_irq_threshold ) ;
spin_lock ( instance - > ctrl_reg_lock ) ;
tmp = inl ( instance - > ctrl_reg ) ;
//In this moment we are sure that SC will come more than once.
tmp | = ME4600_AI_CTRL_BIT_SC_RELOAD ;
if ( instance - > fifo_irq_threshold < ME4600_AI_FIFO_MAX_SC ) { //The threshold is so small that we do need HF.
tmp & = ~ ME4600_AI_CTRL_BIT_SC_IRQ_RESET ;
instance - > ISM . next =
instance - > fifo_irq_threshold ;
} else { //The threshold is large. The HF must be use.
tmp & =
~ ( ME4600_AI_CTRL_BIT_SC_IRQ_RESET |
ME4600_AI_CTRL_BIT_HF_IRQ_RESET ) ;
instance - > ISM . next =
instance - > fifo_irq_threshold %
ME4600_AI_FIFO_HALF ;
if ( instance - > ISM . next + ME4600_AI_FIFO_HALF <
ME4600_AI_FIFO_MAX_SC ) {
instance - > ISM . next + =
ME4600_AI_FIFO_HALF ;
}
}
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base ,
tmp ) ;
spin_unlock ( instance - > ctrl_reg_lock ) ;
}
}
}
2009-03-16 17:45:13 +01:00
static int ai_mux_toggler ( me4600_ai_subdevice_t * instance )
2008-11-01 00:39:12 +01:00
{
uint32_t tmp ;
PDEBUG ( " executed. idx=0 \n " ) ;
outl ( 0 , instance - > scan_pre_timer_low_reg ) ;
PDEBUG_REG ( " scan_pre_timer_low_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_pre_timer_low_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_pre_timer_high_reg ) ;
PDEBUG_REG ( " scan_pre_timer_high_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_pre_timer_high_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_timer_low_reg ) ;
PDEBUG_REG ( " scan_timer_low_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_low_reg - instance - > reg_base , 0 ) ;
outl ( 0 , instance - > scan_timer_high_reg ) ;
PDEBUG_REG ( " scan_timer_high_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > scan_timer_high_reg - instance - > reg_base , 0 ) ;
outl ( 65 , instance - > chan_timer_reg ) ;
PDEBUG_REG ( " chan_timer_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > chan_timer_reg - instance - > reg_base , 65 ) ;
outl ( 65 , instance - > chan_pre_timer_reg ) ;
PDEBUG_REG ( " chan_pre_timer_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > chan_pre_timer_reg - instance - > reg_base , 65 ) ;
// Turn on internal reference.
tmp = inl ( instance - > ctrl_reg ) ;
tmp | = ME4600_AI_CTRL_BIT_FULLSCALE ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
// Clear data and channel fifo.
tmp & =
~ ( ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO ) ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
tmp | = ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
// Write channel entry.
outl ( ME4600_AI_LIST_INPUT_DIFFERENTIAL |
ME4600_AI_LIST_RANGE_UNIPOLAR_2_5 | 31 ,
instance - > channel_list_reg ) ;
PDEBUG_REG ( " channel_list_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > channel_list_reg - instance - > reg_base ,
ME4600_AI_LIST_INPUT_DIFFERENTIAL |
ME4600_AI_LIST_RANGE_UNIPOLAR_2_5 | 31 ) ;
// Start conversion.
inl ( instance - > start_reg ) ;
PDEBUG_REG ( " start_reg inl(0x%lX+0x%lX) \n " , instance - > reg_base ,
instance - > start_reg - instance - > reg_base ) ;
udelay ( 10 ) ;
// Clear data and channel fifo.
tmp & =
~ ( ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO ) ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
tmp | = ME4600_AI_CTRL_BIT_CHANNEL_FIFO | ME4600_AI_CTRL_BIT_DATA_FIFO ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
// Write channel entry.
// ME4600_AI_LIST_INPUT_SINGLE_ENDED | ME4600_AI_LIST_RANGE_BIPOLAR_10 <= 0x0000
outl ( ME4600_AI_LIST_INPUT_SINGLE_ENDED |
ME4600_AI_LIST_RANGE_BIPOLAR_10 , instance - > channel_list_reg ) ;
PDEBUG_REG ( " channel_list_reg outl(0x%lX+0x%lX)=0x%x \n " ,
instance - > reg_base ,
instance - > channel_list_reg - instance - > reg_base ,
ME4600_AI_LIST_INPUT_SINGLE_ENDED |
ME4600_AI_LIST_RANGE_BIPOLAR_10 ) ;
// Start conversion.
inl ( instance - > start_reg ) ;
PDEBUG_REG ( " start_reg inl(0x%lX+0x%lX) \n " , instance - > reg_base ,
instance - > start_reg - instance - > reg_base ) ;
udelay ( 10 ) ;
// Clear control register.
tmp & = ( ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET ) ;
outl ( tmp , instance - > ctrl_reg ) ;
PDEBUG_REG ( " ctrl_reg outl(0x%lX+0x%lX)=0x%x \n " , instance - > reg_base ,
instance - > ctrl_reg - instance - > reg_base , tmp ) ;
return ME_ERRNO_SUCCESS ;
}
/** @brief Copy rest of data from fifo to circular buffer.
* @ note Helper for STOP command . After FSM is stopped .
* @ note This is slow function that copy all remainig data from FIFO to buffer .
*
* @ param instance The subdevice instance ( pointer ) .
*
* @ return On success : Number of copied values .
* @ return On error : Negative error code - ME_ERRNO_RING_BUFFER_OVERFLOW .
*/
2009-03-16 17:45:13 +01:00
static inline int ai_read_data_pooling ( me4600_ai_subdevice_t * instance )
2008-11-01 00:39:12 +01:00
{ /// @note This is time critical function!
int empty_space ;
int copied = 0 ;
int status = ME_ERRNO_SUCCESS ;
PDEBUG ( " Space left in circular buffer = %d. \n " ,
me_circ_buf_space ( & instance - > circ_buf ) ) ;
while ( ( empty_space = me_circ_buf_space ( & instance - > circ_buf ) ) ) {
if ( ! ( status = inl ( instance - > status_reg ) & ME4600_AI_STATUS_BIT_EF_DATA ) ) { //No more data. status = ME_ERRNO_SUCCESS = 0
break ;
}
* ( instance - > circ_buf . buf + instance - > circ_buf . head ) =
( inw ( instance - > data_reg ) ^ 0x8000 ) ;
instance - > circ_buf . head + + ;
instance - > circ_buf . head & = instance - > circ_buf . mask ;
}
# ifdef MEDEBUG_ERROR
if ( ! status )
PDEBUG
( " Copied all remaining datas (%d) from FIFO to circular buffer. \n " ,
copied ) ;
else {
PDEBUG ( " No more empty space in buffer. \n " ) ;
PDEBUG ( " Copied %d datas from FIFO to circular buffer. \n " ,
copied ) ;
PDEBUG ( " FIFO still not empty. \n " ) ;
}
# endif
return ( ! status ) ? copied : - ME_ERRNO_RING_BUFFER_OVERFLOW ;
}
static void me4600_ai_work_control_task ( struct work_struct * work )
{
me4600_ai_subdevice_t * instance ;
uint32_t status ;
uint32_t ctrl ;
unsigned long cpu_flags = 0 ;
int reschedule = 0 ;
int signaling = 0 ;
instance =
container_of ( ( void * ) work , me4600_ai_subdevice_t , ai_control_task ) ;
2009-01-07 23:31:57 +01:00
PINFO ( " <%s: %ld> executed. \n " , __func__ , jiffies ) ;
2008-11-01 00:39:12 +01:00
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 ) ;
switch ( instance - > status ) { // Checking actual mode.
// Not configured for work.
case ai_status_none :
break ;
//This are stable modes. No need to do anything. (?)
case ai_status_single_configured :
case ai_status_stream_configured :
case ai_status_stream_fifo_error :
case ai_status_stream_buffer_error :
case ai_status_stream_error :
PERROR ( " Shouldn't be running!. \n " ) ;
break ;
// Stream modes
case ai_status_stream_run_wait :
if ( status & ME4600_AI_STATUS_BIT_FSM ) { // ISM started..
instance - > status = ai_status_stream_run ;
// Signal the end of wait for start.
signaling = 1 ;
// Wait now 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. Reset FIFO => Too late!
ai_stop_isr ( instance ) ;
instance - > status = ai_status_stream_end ;
// Signal the end.
signaling = 1 ;
}
}
break ;
case ai_status_stream_run :
// Wait for stop ISM.
reschedule = 1 ;
break ;
case ai_status_stream_end_wait :
if ( ! ( status & ME4600_AI_STATUS_BIT_FSM ) ) { // ISM stoped. Overwrite ISR.
instance - > status = ai_status_stream_end ;
// Signal the end of wait for stop.
signaling = 1 ;
} else {
// Wait for stop ISM.
reschedule = 1 ;
}
break ;
case ai_status_stream_end :
//End work.
if ( status & ME4600_AI_STATUS_BIT_FSM ) { // Still working? Stop it!
PERROR
( " Status is 'ai_status_stream_end' but hardware is still working! \n " ) ;
spin_lock_irqsave ( instance - > ctrl_reg_lock , cpu_flags ) ;
ctrl = inl ( instance - > ctrl_reg ) ;
ctrl | =
( ME4600_AI_CTRL_BIT_IMMEDIATE_STOP |
ME4600_AI_CTRL_BIT_HF_IRQ_RESET |
ME4600_AI_CTRL_BIT_SC_IRQ_RESET ) ;
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 - > ctrl_reg_lock ,
cpu_flags ) ;
}
break ;
default :
PERROR_CRITICAL ( " Status is in wrong state (%d)! \n " ,
instance - > status ) ;
instance - > status = ai_status_stream_error ;
// Signal the end.
signaling = 1 ;
break ;
}
if ( signaling ) { //Signal it.
wake_up_interruptible_all ( & instance - > wait_queue ) ;
}
if ( instance - > ai_control_task_flag & & reschedule ) { // Reschedule task
queue_delayed_work ( instance - > me4600_workqueue ,
& instance - > ai_control_task , 1 ) ;
} else {
2009-01-07 23:31:57 +01:00
PINFO ( " <%s> Ending control task. \n " , __func__ ) ;
2008-11-01 00:39:12 +01:00
}
}