Changed prototype of RT version of comedi_request_irq to make dev_id a comedi_device* instead of a void*
since it is assumed to be so elsewhere in rt code. Made comedi_switch_to_rt return an int
so it is able to return error on failure. Fixes for overrun/underrun checking with dma in ni_mio_common.
if(!async){
DPRINTK("subdevice does not have async capability\n");
- bi.buf_int_ptr = 0;
- bi.buf_user_ptr = 0;
- bi.buf_int_count = 0;
- bi.buf_user_count = 0;
+ bi.buf_write_ptr = 0;
+ bi.buf_read_ptr = 0;
+ bi.buf_write_count = 0;
+ bi.buf_read_count = 0;
goto copyback;
}
}
}
- // XXX fix bufinfo struct
- bi.buf_int_count = async->buf_write_count;
- bi.buf_int_ptr = async->buf_write_ptr;
- bi.buf_user_count = async->buf_read_count;
- bi.buf_user_ptr = async->buf_read_ptr;
+ if(bi.bytes_written){
+ bi.bytes_written = comedi_buf_write_alloc( async, bi.bytes_written );
+ comedi_buf_munge(dev, s, bi.bytes_written);
+ comedi_buf_write_free(async, bi.bytes_written);
+ }
+
+ bi.buf_write_count = async->buf_write_count;
+ bi.buf_write_ptr = async->buf_write_ptr;
+ bi.buf_read_count = async->buf_read_count;
+ bi.buf_read_ptr = async->buf_read_ptr;
copyback:
if(copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))
n -= m;
retval = -EFAULT;
}
- if( s->munge ){
- s->munge(dev, s,async->prealloc_buf + async->buf_write_ptr, n);
- }
+ comedi_buf_munge(dev, s, n);
comedi_buf_write_free(async, n);
count+=n;
continue;
}
- if( s->munge ){
- s->munge(dev, s, async->prealloc_buf +
- async->buf_read_ptr, n);
- }
m = copy_to_user(buf, async->prealloc_buf +
async->buf_read_ptr, n);
if(m){
static void init_async_buf( comedi_async *async )
{
- async->buf_free_count = 0;
+ async->buf_write_alloc_count = 0;
async->buf_write_count = 0;
async->buf_read_count = 0;
async->cur_chan = 0;
async->scan_progress = 0;
+ async->munge_chan = 0;
}
EXPORT_SYMBOL(comedi_buf_get);
EXPORT_SYMBOL(comedi_buf_read_n_available);
EXPORT_SYMBOL(comedi_buf_write_free);
+EXPORT_SYMBOL(comedi_buf_munge);
EXPORT_SYMBOL(comedi_buf_write_alloc);
EXPORT_SYMBOL(comedi_buf_read_free);
EXPORT_SYMBOL(comedi_buf_memcpy_to);
return 0;
}
+// munging is applied to data right before comedi_buf_write_free()
+void comedi_buf_munge( comedi_device *dev, comedi_subdevice *s,
+ unsigned int num_bytes )
+{
+ unsigned int offset = s->async->buf_write_count;
+
+ if( s->munge == NULL || ( s->async->cmd.flags & CMDF_RAWDATA ) )
+ return;
+
+ while( num_bytes )
+ {
+ unsigned int block_size;
+
+ block_size = num_bytes;
+ if( (int)(offset + block_size - s->async->prealloc_bufsz) > 0 )
+ block_size = s->async->prealloc_bufsz - offset;
+
+ s->munge( dev, s, s->async->prealloc_buf + offset,
+ block_size, s->async->munge_chan );
+
+ s->async->munge_chan += num_bytes / bytes_per_sample( s );
+ s->async->munge_chan %= s->async->cmd.chanlist_len;
+ num_bytes -= block_size;
+ offset = 0;
+ }
+}
+
unsigned int comedi_buf_write_n_available(comedi_async *async)
{
unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
- return free_end - async->buf_free_count;
+ return free_end - async->buf_write_alloc_count;
}
unsigned int comedi_buf_write_alloc(comedi_async *async, unsigned int nbytes)
{
unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
- if((int)(async->buf_free_count + nbytes - free_end) > 0){
- nbytes = free_end - async->buf_free_count;
+ if((int)(async->buf_write_alloc_count + nbytes - free_end) > 0){
+ nbytes = free_end - async->buf_write_alloc_count;
}
- async->buf_free_count += nbytes;
+ async->buf_write_alloc_count += nbytes;
return nbytes;
}
{
unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
- if((int)(async->buf_free_count + nbytes - free_end) > 0){
+ if((int)(async->buf_write_alloc_count + nbytes - free_end) > 0){
nbytes = 0;
}
- async->buf_free_count += nbytes;
+ async->buf_write_alloc_count += nbytes;
return nbytes;
}
async->buf_write_count += nbytes;
async->buf_write_ptr += nbytes;
if(async->buf_write_ptr >= async->prealloc_bufsz){
- async->buf_write_ptr -= async->prealloc_bufsz;
+ async->buf_write_ptr %= async->prealloc_bufsz;
async->events |= COMEDI_CB_EOBUF;
}
}
#include <linux/module.h>
#include <linux/kernel.h>
#include "comedi_fc.h"
-
-static inline unsigned int bytes_per_sample( comedi_subdevice *subd )
-{
- if( subd->flags & SDF_LSAMPL )
- return sizeof( lsampl_t );
- else
- return sizeof( sampl_t );
-}
+#include "linux/comedidev.h"
static inline unsigned int bytes_per_scan( comedi_subdevice *subd )
{
int count;
comedi_subdevice *s = dev->subdevices + 0;
comedi_async *async = s->async;
- unsigned int nbytes;
- int ret;
+ unsigned int nbytes, old_alloc_count;
writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(AI_DMA_CHAN));
+ old_alloc_count = async->buf_write_alloc_count;
+ // write alloc as much as we can
+ comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
+
nbytes = mite_bytes_transferred(mite, AI_DMA_CHAN);
- if((int)(nbytes - async->buf_free_count) >= 0){
+ if( (int)(nbytes - old_alloc_count) > 0 ){
printk("ni_mio_common: BUG: DMA overwrite of free area\n");
ni_ai_reset(dev,s);
async->events |= COMEDI_CB_OVERFLOW;
}
count = nbytes - async->buf_write_count;
+ if( count < 0 ){
+ rt_printk("ni_mio_common: BUG: negative ai count\n");
+ count = 0;
+ }
+ comedi_buf_munge(dev, s, count);
comedi_buf_write_free(async, count);
- while( count ){
- unsigned int block_size;
-
- block_size = count;
-
- ret = comedi_buf_write_alloc(s->async, block_size);
- if(ret == 0){
- printk("ni_mio_common: buffer overflow\n");
- ni_ai_reset(dev,s);
- async->events |= COMEDI_CB_OVERFLOW;
- break;
- }
-
- count -= ret;
- }
-
async->events |= COMEDI_CB_BLOCK;
}
int count;
comedi_subdevice *s = dev->subdevices + 1;
comedi_async *async = s->async;
- unsigned int nbytes;
+ unsigned int nbytes, new_write_count;
writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(AO_DMA_CHAN));
+ new_write_count = async->buf_write_count;
+
nbytes = mite_bytes_read(mite, AO_DMA_CHAN);
- // XXX this won't catch all buffer underruns
- if((int)(nbytes - async->buf_write_count) > 0){
+ if( (int)(nbytes - devpriv->last_buf_write_count) > 0 ){
rt_printk("ni_mio_common: DMA underrun\n");
- rt_printk("nbytes %u, write count %u\n", nbytes, async->buf_write_count );
ni_ao_reset(dev,s);
async->events |= COMEDI_CB_OVERFLOW;
return;
}
+ devpriv->last_buf_write_count = new_write_count;
+
count = nbytes - async->buf_read_count;
if( count < 0 ){
- rt_printk("ni_mio_common: BUG: negative count\n");
+ rt_printk("ni_mio_common: BUG: negative ao count\n");
count = 0;
}
comedi_buf_read_free(async, count);
}
static void ni_ai_munge(comedi_device *dev, comedi_subdevice *s,
- void *data, unsigned int num_bytes)
+ void *data, unsigned int num_bytes, unsigned int chan_index )
{
comedi_async *async = s->async;
unsigned int i;
array[i] = __le16_to_cpu(array[i]);
#endif
array[i] ^= devpriv->ai_xorlist[ async->cur_chan ];
- async->cur_chan++;
- async->cur_chan %= async->cmd.chanlist_len;
+ chan_index++;
+ chan_index %= async->cmd.chanlist_len;
}
}
struct mite_channel *mite_chan = &mite->channels[ AI_DMA_CHAN ];
comedi_subdevice *s = dev->subdevices + 0;
- /* mark 4 pages as being under DMA control */
- comedi_buf_write_alloc(s->async, 4*PAGE_SIZE);
+ /* write alloc the entire buffer */
+ comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
mite_chan->current_link = 0;
mite_chan->dir = COMEDI_INPUT;
{
struct mite_struct *mite = devpriv->mite;
struct mite_channel *mite_chan = &mite->channels[ AO_DMA_CHAN ];
+ comedi_subdevice *s = dev->subdevices + 1;
+
+ devpriv->last_buf_write_count = s->async->buf_write_count;
mite_chan->current_link = 0;
mite_chan->dir = COMEDI_OUTPUT;
#ifdef PCIDMA
mite_dma_disarm(devpriv->mite, AI_DMA_CHAN);
#endif
+ win_out(AI_Reset,Joint_Reset_Register);
+ /* ai configuration */
+ win_out(AI_Configuration_Start,Joint_Reset_Register);
+
ni_set_bits(dev, Interrupt_A_Enable_Register,
AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|
AI_START2_Interrupt_Enable| AI_START_Interrupt_Enable|
AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable|
AI_FIFO_Interrupt_Enable,0);
- win_out(AI_Reset,Joint_Reset_Register);
+ // XXX do interrupt ack
win_out(1,ADC_FIFO_Clear);
- /* ai configuration */
-
- win_out(AI_Configuration_Start,Joint_Reset_Register);
-
ni_writeb(0, Misc_Command);
win_out(0x0000,AI_Command_1_Register); /* reset pulses */
- win_out(0x000d,AI_Mode_1_Register);
+ win_out(AI_Start_Stop | AI_Mode_1_Reserved | AI_Trigger_Once,
+ AI_Mode_1_Register);
win_out(0x0000,AI_Mode_2_Register);
#if 0
/* generate FIFO interrupts on half full */
mask=(1<<boardtype.adbits)-1;
signbits=devpriv->ai_xorlist[0];
for(n=0;n<insn->n;n++){
- win_out(1,AI_Command_1_Register);
+ win_out(AI_CONVERT_Pulse, AI_Command_1_Register);
if(boardtype.reg_611x){
/* The 611x has screwy 32-bit FIFOs. */
for(i=0;i<NI_TIMEOUT;i++){
ni_writew(CR_CHAN(list[i])&0x0003, Calibration_Channel_Select_611x);
}else
{
+ if( boardtype.reg_611x )
+ aref = AREF_DIFF;
switch( aref )
{
case AREF_DIFF:
switch(cmd->scan_begin_src){
case TRIG_TIMER:
- /* AI_SI2_Arm, AI_SI_Arm, AI_DIV_Arm, AI_SC_Arm */
- win_out(0x1540,AI_Command_1_Register);
+ win_out(AI_SI2_Arm | AI_SI_Arm | AI_DIV_Arm | AI_SC_Arm,
+ AI_Command_1_Register);
break;
case TRIG_EXT:
- /* AI_SI2_Arm, AI_DIV_Arm, AI_SC_Arm */
- win_out(0x1540,AI_Command_1_Register);
+ /* XXX AI_SI_Arm? */
+ win_out(AI_SI2_Arm | AI_SI_Arm | AI_DIV_Arm | AI_SC_Arm,
+ AI_Command_1_Register);
break;
}
/* munge data from unsigned to 2's complement for analog output bipolar modes */
static void ni_ao_munge(comedi_device *dev, comedi_subdevice *s,
- void *data, unsigned int num_bytes)
+ void *data, unsigned int num_bytes, unsigned int chan_index )
{
comedi_async *async = s->async;
unsigned int range;
offset = 1 << (boardtype.aobits - 1);
for(i = 0; i < length; i++)
{
- range = CR_RANGE( async->cmd.chanlist[ async->cur_chan ] );
+ range = CR_RANGE( async->cmd.chanlist[ chan_index ] );
if(boardtype.ao_unipolar == 0 || (range & 1) == 0 )
array[i] -= offset;
#ifdef PCIDMA
array[i] = __cpu_to_le16( array[i] );
#endif
- async->cur_chan++;
- async->cur_chan %= async->cmd.chanlist_len;
+ chan_index++;
+ chan_index %= async->cmd.chanlist_len;
}
}
trigvar = ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
+ win_out(AO_Configuration_Start,Joint_Reset_Register);
+
win_out(AO_Disarm,AO_Command_1_Register);
ni_ao_config_chanlist(dev,s,cmd->chanlist,cmd->chanlist_len);
- win_out(AO_Configuration_Start,Joint_Reset_Register);
-
devpriv->ao_mode1|=AO_Trigger_Once;
win_out(devpriv->ao_mode1,AO_Mode_1_Register);
devpriv->ao_trigger_select&=~(AO_START1_Polarity|AO_START1_Select(-1));
NI_PRIVATE_COMMON
- dma_addr_t ai_dma_handle;
+ unsigned int last_buf_write_count;
}ni_private;
#define devpriv ((ni_private *)dev->private)
{
async->buf_read_count = 0;
async->buf_write_count = 0;
- async->buf_free_count = 0;
+ async->buf_write_alloc_count = 0;
async->buf_read_ptr = 0;
async->buf_write_ptr = 0;
async->cur_chan = 0;
async->scan_progress = 0;
+ async->munge_chan = 0;
}
int comedi_command(comedi_t *d,comedi_cmd *cmd)
void (*handler)(int irq,void *dev_id,struct pt_regs *regs);
unsigned long flags;
const char *device;
- void *dev_id;
+ comedi_device *dev_id;
};
static int rt_get_irq(struct comedi_irq_struct *it);
#define MAX_IRQ_SHARING 6
static struct comedi_irq_struct *comedi_irqs[NR_IRQS][MAX_IRQ_SHARING];
-struct comedi_irq_struct * find_comedi_irq_struct( int irq, void *dev_id )
+static struct comedi_irq_struct * find_comedi_irq_struct( int irq, comedi_device *dev_id )
{
int i;
return NULL;
}
-void free_comedi_irq_struct( int irq, void *dev_id )
+static void free_comedi_irq_struct( int irq, comedi_device *dev_id )
{
int i;
}
}
+static int insert_comedi_irq_struct( int irq,
+ struct comedi_irq_struct *it )
+{
+ int i;
+
+ for( i = 0; i < MAX_IRQ_SHARING; i++ )
+ {
+ if( comedi_irqs[ irq ][ i ] == NULL )
+ {
+ comedi_irqs[ irq ][ i ] = it;
+ return 0;
+ }
+ }
+ return -1;
+}
+
int comedi_request_irq(unsigned irq,void (*handler)(int, void *,struct pt_regs *),
- unsigned long flags,const char *device,void *dev_id)
+ unsigned long flags,const char *device,comedi_device *dev_id)
{
struct comedi_irq_struct *it;
int ret;
- int i;
it=kmalloc(sizeof(*it),GFP_KERNEL);
if(!it)
}
}
- for( i = 0; i < MAX_IRQ_SHARING; i++)
- {
- if( comedi_irqs[irq][i] == NULL )
- {
- comedi_irqs[irq][i] = it;
- break;
- }
- }
- if( i == MAX_IRQ_SHARING )
+ if( insert_comedi_irq_struct( irq, it ) )
{
kfree(it);
return -1;
return 0;
}
-void comedi_free_irq(unsigned int irq,void *dev_id)
+void comedi_free_irq(unsigned int irq,comedi_device *dev_id)
{
struct comedi_irq_struct *it;
-void comedi_switch_to_rt(comedi_device *dev)
+int comedi_switch_to_rt(comedi_device *dev)
{
struct comedi_irq_struct *it;
unsigned long flags;
- it = find_comedi_irq_struct( dev->irq, dev ); // assumes dev == dev_id XXX
+ it = find_comedi_irq_struct( dev->irq, dev );
/* drivers might not be using an interrupt for commands */
- if( it == NULL ) return;
+ if( it == NULL ) return -1;
/* rt interrupts and shared interrupts don't mix */
if(it->flags & SA_SHIRQ){
- printk("comedi: cannot switch shared interrupt to real time priority\n");
- return;
+ DPRINTK( "cannot switch shared interrupt to real time priority\n" );
+ return -1;
}
comedi_spin_lock_irqsave( &dev->spinlock, flags );
it->rt=1;
comedi_spin_unlock_irqrestore( &dev->spinlock, flags );
+
+ return 0;
}
void comedi_switch_to_non_rt(comedi_device *dev)
struct comedi_irq_struct *it;
unsigned long flags;
- it = find_comedi_irq_struct( dev->irq, dev ); // assumes dev == dev_id XXX
+ it = find_comedi_irq_struct( dev->irq, dev );
if(it == NULL)
return;
unsigned int subdevice;
unsigned int bytes_read;
- unsigned int buf_int_ptr;
- unsigned int buf_user_ptr;
- unsigned int buf_int_count;
- unsigned int buf_user_count;
+ unsigned int buf_write_ptr;
+ unsigned int buf_read_ptr;
+ unsigned int buf_write_count;
+ unsigned int buf_read_count;
- unsigned int unused[5];
+ unsigned int bytes_written;
+
+ unsigned int unused[4];
};
/* range stuff */
int comedi_request_irq(unsigned int irq,void (*handler)(int,void *,
struct pt_regs *regs),unsigned long flags,const char *device,
- void *dev_id);
-void comedi_free_irq(unsigned int irq,void *dev_id);
+ comedi_device *dev_id);
+void comedi_free_irq(unsigned int irq,comedi_device *dev_id);
void comedi_rt_init(void);
void comedi_rt_cleanup(void);
-void comedi_switch_to_rt(comedi_device *dev);
+int comedi_switch_to_rt(comedi_device *dev);
void comedi_switch_to_non_rt(comedi_device *dev);
void comedi_rt_pend_wakeup(wait_queue_head_t *q);
extern int rt_pend_call(void (*func)(int arg1, void * arg2), int arg1, void * arg2);
int (*buf_alloc)(comedi_device *,comedi_subdevice *s,unsigned long new_size);
void (*munge)( comedi_device *, comedi_subdevice *s, void *data,
- unsigned int num_bytes );
+ unsigned int num_bytes, unsigned int start_chan_index );
unsigned int state;
};
unsigned int max_bufsize; /* maximum buffer size, bytes */
unsigned int mmap_count; /* current number of mmaps of prealloc_buf */
- volatile unsigned int buf_free_count; /* byte count for free space */
volatile unsigned int buf_write_count; /* byte count for writer (write completed) */
- volatile unsigned int buf_read_count; /* byte count for reader */
+ volatile unsigned int buf_write_alloc_count; /* byte count for writer (allocated for writing) */
+ volatile unsigned int buf_read_count; /* byte count for reader (read completed)*/
unsigned int buf_write_ptr; /* buffer marker for writer */
unsigned int buf_read_ptr; /* buffer marker for reader */
unsigned int cur_chan; /* useless channel marker for interrupt */
/* number of bytes that have been received for current scan */
unsigned int scan_progress;
+ /* keeps track of where we are in chanlist as for munging */
+ unsigned int munge_chan;
unsigned int events; /* events that have occurred */
return 0;
}
+static inline unsigned int bytes_per_sample( const comedi_subdevice *subd )
+{
+ if( subd->flags & SDF_LSAMPL )
+ return sizeof( lsampl_t );
+ else
+ return sizeof( sampl_t );
+}
+
#if 0
int write_to_async_buffer( comedi_async *async, const void *array,
unsigned int num_bytes, unsigned int from_user_space );
unsigned int num_bytes );
void comedi_buf_memcpy_from( comedi_async *async, unsigned int offset, void *destination,
unsigned int num_bytes );
-
+void comedi_buf_munge( comedi_device *dev, comedi_subdevice *s,
+ unsigned int num_bytes );
//#ifdef CONFIG_COMEDI_RT
#include <linux/comedi_rt.h>