static int do_cancel(comedi_device *dev,comedi_subdevice *s);
static int comedi_fasync (int fd, struct file *file, int on);
+static void init_async_buf( comedi_async *async );
static int comedi_ioctl(struct inode * inode,struct file * file,
unsigned int cmd,unsigned long arg)
if(bi.bytes_read){
// check for buffer underflow
- m = async->buf_int_count - async->buf_user_count;
+ m = async->buf_write_count - async->buf_read_count;
if(bi.bytes_read > m)
{
DPRINTK("buffer underflow\n");
return -EIO;
}
- async->buf_user_ptr += bi.bytes_read;
- async->buf_user_count += bi.bytes_read;
+ async->buf_read_ptr += bi.bytes_read;
+ if( async->buf_read_ptr >= async->data_len )
+ async->buf_read_ptr %= async->data_len;
+ async->buf_read_count += bi.bytes_read;
// check for buffer overflow
- if(m > async->data_len){
- async->buf_user_count = async->buf_int_count;
- async->buf_user_ptr = async->buf_int_ptr;
+ if( m > async->data_len )
+ {
do_cancel(dev, dev->read_subdev);
DPRINTK("buffer overflow\n");
return -EIO;
}
- if(!(s->subdev_flags&SDF_RUNNING) && async->buf_int_count==async->buf_user_count){
+ if(!(s->subdev_flags&SDF_RUNNING) && async->buf_write_count==async->buf_read_count){
do_become_nonbusy(dev,s);
}
}
- bi.buf_int_count = async->buf_int_count;
- bi.buf_int_ptr = async->buf_int_ptr;
- bi.buf_user_count = async->buf_user_count;
- bi.buf_user_ptr = async->buf_user_ptr;
+ // 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;
copyback:
if(copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))
async->cmd.data_len=async->prealloc_bufsz;
#endif
- async->data = async->prealloc_buf;
- async->data_len=async->prealloc_bufsz;
-
- async->buf_int_ptr=0;
- async->buf_int_count=0;
- async->buf_user_ptr=0;
- async->buf_user_count=0;
+ init_async_buf( async );
async->cur_chan = 0;
+ async->data = async->prealloc_buf;
+ async->data_len=async->prealloc_bufsz;
+
async->cb_mask = COMEDI_CB_EOA|COMEDI_CB_BLOCK|COMEDI_CB_ERROR;
if(async->cmd.flags & TRIG_WAKE_EOS){
async->cb_mask |= COMEDI_CB_EOS;
}
+
async->events = 0;
s->runflags=SRF_USER;
reads:
nothing
-
+
writes:
nothing
s = dev->read_subdev;
async = s->async;
if(!s->busy ||
- (async->buf_user_count < async->buf_int_count) ||
+ (async->buf_read_count < async->buf_write_count) ||
!(s->subdev_flags&SDF_RUNNING)){
mask |= POLLIN | POLLRDNORM;
}
async = s->async;
if(!s->busy ||
!(s->subdev_flags&SDF_RUNNING) ||
- (async->buf_user_count < async->buf_int_count +
+ (async->buf_write_count < async->buf_read_count +
async->prealloc_bufsz)){
mask |= POLLOUT | POLLWRNORM;
}
n=nbytes;
- m = async->data_len + async->buf_int_count - async->buf_user_count;
- if( async->buf_user_ptr + m > async->data_len )
- m = async->data_len - async->buf_user_ptr;
+ m = async->data_len + async->buf_read_count - async->buf_write_count;
+ if( async->buf_write_ptr + m > async->data_len )
+ m = async->data_len - async->buf_write_ptr;
if(m < n) n = m;
schedule();
continue;
}
- m=copy_from_user(async->data+async->buf_user_ptr,buf,n);
- if(m) retval=-EFAULT;
+ m = 0;
+ if( write_to_async_buffer( async, buf, n, 1 ) )
+ {
+ m = n;
+ retval = -EFAULT;
+ }
n-=m;
count+=n;
nbytes-=n;
- async->buf_user_ptr+=n;
- async->buf_user_count+=n;
-
- if(async->buf_user_ptr>=async->data_len ){
- async->buf_user_ptr=0;
- }
buf+=n;
break; /* makes device work like a pipe */
n=nbytes;
- m = async->buf_int_ptr - async->buf_user_ptr;
- if( m < 0 )
- m = async->data_len - async->buf_user_ptr;
+ m = async->buf_write_count - async->buf_read_count;
+ if( m > async->data_len )
+ m = async->data_len;
#if 0
printk("m is %d\n",m);
schedule();
continue;
}
- m=copy_to_user(buf,async->data+async->buf_user_ptr,n);
- if(m) retval=-EFAULT;
+ m=0;
+ retval = read_from_async_buffer( async, buf, n, 1 );
+ if( retval )
+ {
+ m = n;
+ }
n-=m;
/* check for buffer overflow */
- if(async->buf_int_count - async->buf_user_count > async->data_len){
- async->buf_user_count = async->buf_int_count;
- async->buf_user_ptr = async->buf_int_ptr;
- retval=-EIO;
+ if( retval == -EIO )
+ {
do_cancel(dev, dev->read_subdev);
DPRINTK("buffer overflow\n");
break;
count+=n;
nbytes-=n;
- async->buf_user_ptr+=n;
- async->buf_user_count+=n;
-
- if(async->buf_user_ptr>=async->data_len ){
- async->buf_user_ptr=0;
- }
buf+=n;
break; /* makes device work like a pipe */
}
if(!(s->subdev_flags&SDF_RUNNING) &&
!(s->runflags & SRF_ERROR) &&
- async->buf_int_count - async->buf_user_count == 0)
+ async->buf_read_count - async->buf_write_count == 0)
{
do_become_nonbusy(dev,s);
}
#endif
if(async){
- async->buf_user_ptr=0;
- async->buf_int_ptr=0;
- async->buf_user_count=0;
- async->buf_int_count=0;
+ init_async_buf( async );
}else{
printk("BUG: (?) do_become_nonbusy called with async=0\n");
}
}
}
+static void init_async_buf( comedi_async *async )
+{
+ async->buf_read_count = 0;
+ async->buf_write_count = 0;
+ async->buf_dirty_count = 0;
+ async->buf_read_ptr = 0;
+ async->buf_write_ptr = 0;
+}
+
unsigned char cnt0_users; // bit field of 8254 CNT0 users (0-unused, 1-AO, 2-DI, 3-DO)
unsigned char exttrg_users; // bit field of external trigger users (0-AI, 1-AO, 2-DI, 3-DO)
unsigned int cnt0_divisor; // actual CNT0 divisor
- int (*dma_ai_read_block)(comedi_device *, comedi_subdevice *, lsampl_t **, lsampl_t *, unsigned int *, unsigned int *); // ptr to actual transfer function from DMA buffer
+ int (*dma_ai_read_block)(comedi_device *, comedi_subdevice *, void *, int *, int *); // ptr to actual transfer function from DMA buffer
void (*int_ai_func)(comedi_device *, comedi_subdevice *,unsigned short, unsigned int, unsigned short); // ptr to actual interrupt AI function
unsigned char ai16bits; // =1 16 bit card
unsigned char usedma; // =1 use DMA transfer and not INT
static int pci9118_ai_cancel(comedi_device * dev, comedi_subdevice * s);
static void pci9118_calc_divisors(char mode, comedi_device * dev, comedi_subdevice * s,
unsigned int *tim1, unsigned int *tim2, unsigned int flags,
- int chans, unsigned int *div1, unsigned int *div2,
+ int chans, unsigned int *div1, unsigned int *div2,
char usessh, unsigned int chnsshfront);
/*
static int pci9118_insn_write_ao(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data)
{
int n,chanreg,ch;
-
+
ch=CR_CHAN(insn->chanspec);
if (ch) { chanreg=PCI9118_DA2;}
else { chanreg=PCI9118_DA1; }
return 2;
}
-/*
+/*
==============================================================================
*/
static void interrupt_pci9118_ai_mode4_switch(comedi_device *dev)
return -1;
}
-/*
+/*
==============================================================================
*/
static int move_block_from_dma_12bit_16b(comedi_device *dev, comedi_subdevice *s,
- sampl_t **dma, sampl_t *data, int *sampls, int *bufs)
+ void *dma_void, int *sampls, int *bufs)
{
unsigned int cc,sp,chans,chns;
sampl_t sampl;
+ uint16_t **dma = (uint16_t **) dma_void;
cc=s->async->cur_chan;
sp=devpriv->ai_act_scanpos;
for (;cc<chns;cc++) {
sampl=**dma; (*dma)++;
#ifdef PCI9118_PARANOIDCHECK
- if ((sampl & 0x0f00)!=devpriv->chanlist[cc]) {
+ if ((sampl & 0x0f00)!=devpriv->chanlist[cc]) {
rt_printk("comedi: A/D DMA - data dropout: received channel %04x, expected %04x!\n",(sampl & 0x0f00),devpriv->chanlist[cc]);
DPRINTK("comedi: bufs=%d cc=%d sp=%d dmapos=%d chans=%d af=%d ab=%d sampls=%d (dma)=%04x dma=%04x!\n",*bufs,cc,sp,devpriv->ai_act_dmapos,chans,devpriv->ai_add_front,devpriv->ai_add_back,*sampls,*(*dma-1),(int)(*dma-1));
s->async->events|=COMEDI_CB_ERROR|COMEDI_CB_EOA;
}
#endif
sampl=((sampl & 0xff)<<4)|((sampl & 0xf000)>>12); // get one sample
- *data=sampl;
- data++;
+ comedi_buf_put( s->async, sampl);
}
sp+=cc;
if (cc>=chans) {
cc=0;
devpriv->ai_act_dmapos=0;
if (devpriv->ai_add_back) // drop added one
- if (*bufs) {
+ if (*bufs) {
(*bufs)--;
(*dma)++;
}
if(sp>=devpriv->ai_n_scanlen) { // is end of one scan?
sp=0;
devpriv->ai_act_scan++;
- s->async->events|=COMEDI_CB_EOS;
- if (*sampls)
+ if (*sampls)
if (devpriv->ai_flags & TRIG_WAKE_EOS) {
comedi_event(dev,s,s->async->events);
s->async->events=0;
}
// DPRINTK("9 cc=%d sp=%d *bufs=%d *sampls=%d chns=%d/%d dmapos=%d\n",cc,sp,*bufs,*sampls,chns,chans,devpriv->ai_act_dmapos);
devpriv->ai_act_scanpos=sp;
- s->async->cur_chan=cc;
return 0;
}
-/*
+/*
==============================================================================
*/
static int move_block_from_dma_16bit_16b(comedi_device *dev, comedi_subdevice *s,
- sampl_t **dma, sampl_t *data, int *sampls, int *bufs)
+ void *dma_void, int *sampls, int *bufs)
{
unsigned int cc,sp,chans,chns;
sampl_t sampl;
+ uint16_t **dma = (uint16_t **) dma_void;
cc=s->async->cur_chan;
sp=devpriv->ai_act_scanpos;
for (;cc<chns;cc++) {
sampl=**dma; (*dma)++;
sampl=(((sampl & 0xff)<<8)|((sampl & 0xff00)>>8))^0x8000; // get one sample
- *data=sampl;
- data++;
+ comedi_buf_put( s->async, sampl );
}
sp+=cc;
if (cc>=chans) {
cc=0;
devpriv->ai_act_dmapos=0;
if (devpriv->ai_add_back) // drop added one
- if (*bufs) {
+ if (*bufs) {
(*bufs)--;
(*dma)++;
}
if(sp>=devpriv->ai_n_scanlen) { // is end of one scan?
sp=0;
devpriv->ai_act_scan++;
- s->async->events|=COMEDI_CB_EOS;
- if (*sampls)
+ if (*sampls)
if (devpriv->ai_flags & TRIG_WAKE_EOS) {
comedi_event(dev,s,s->async->events);
s->async->events=0;
}
// DPRINTK("9 cc=%d sp=%d *bufs=%d *sampls=%d chns=%d/%d dmapos=%d\n",cc,sp,*bufs,*sampls,chns,chans,devpriv->ai_act_dmapos);
devpriv->ai_act_scanpos=sp;
- s->async->cur_chan=cc;
return 0;
}
-/*
+/*
==============================================================================
Skip a few samples at begin of every scan if is used software generated
sample&hold signal
{
unsigned int n;
- n=(devpriv->ai_add_front-devpriv->ai_act_dmapos)>>1;
+ n=(devpriv->ai_add_front-devpriv->ai_act_dmapos)>>1;
// DPRINTK("n=%d bufs=%d *dma=0x%08x dmapos=%d %d\n",n,*bufs,*dma,devpriv->ai_act_dmapos,x);
if (*bufs>n) {
(*bufs)-=n;
return -1;
}
-/*
+/*
==============================================================================
*/
static int move_block_from_dma_12bit_32b(comedi_device *dev, comedi_subdevice *s,
- lsampl_t **dma, lsampl_t *data, int *sampls, int *bufs)
+ void *dma_void, int *sampls, int *bufs)
{
int cc,sp,chans,chns,xx,yy;
lsampl_t sampl;
#ifdef PCI9118_PARANOIDCHECK
lsampl_t *chanlist=(lsampl_t *)devpriv->chanlist;
#endif
+ uint32_t ** dma = ( uint32_t ** ) dma_void;
cc=s->async->cur_chan;
sp=devpriv->ai_act_scanpos;
for (;cc<chns;cc++) {
sampl=**dma; (*dma)++;
#ifdef PCI9118_PARANOIDCHECK
- if ((sampl & 0x000f000f)!=chanlist[cc]) {
+ if ((sampl & 0x000f000f)!=chanlist[cc]) {
rt_printk("comedi: A/D DMA - data dropout: received channel %08x, expected %08x!\n",(sampl & 0x000f000f),chanlist[cc]);
DPRINTK("comedi: bufs=%d cc=%d sp=%d dmapos=%d chns=%d chans=%d af=%d ab=%d sampls=%d (dma)=%08x dma=%08x!\n",*bufs,cc,sp,devpriv->ai_act_dmapos,chns,chans,devpriv->ai_add_front,devpriv->ai_add_back,*sampls,*(*dma-1),(int)(*dma-1));
s->async->events|=COMEDI_CB_ERROR|COMEDI_CB_EOA;
}
#endif
sampl=((sampl & 0xfff0)<<12)|((sampl & 0xfff00000)>>20);
- *data=sampl;
- data++;
+ comedi_buf_put_long( s->async, sampl );
}
sp+=cc<<1;
if (cc>=chans) {
if(sp>=devpriv->ai_n_scanlen) { // is end of one scan?
sp=0;
devpriv->ai_act_scan++;
- s->async->events|=COMEDI_CB_EOS;
- if (*sampls)
+ if (*sampls)
if (devpriv->ai_flags & TRIG_WAKE_EOS) {
comedi_event(dev,s,s->async->events);
s->async->events=0;
*bufs-=*bufs-(xx<<1);
*sampls-=*sampls-(yy<<1);
devpriv->ai_act_scanpos=sp;
- s->async->cur_chan=cc;
return 0;
}
-/*
+/*
==============================================================================
*/
static int move_block_from_dma_16bit_32b(comedi_device *dev, comedi_subdevice *s,
- lsampl_t **dma, lsampl_t *data, int *sampls, int *bufs)
+ void *dma_void, int *sampls, int *bufs)
{
int cc,sp,chans,chns,xx,yy;
lsampl_t sampl;
+ uint32_t **dma = ( uint32_t ** ) dma_void;
cc=s->async->cur_chan;
sp=devpriv->ai_act_scanpos;
for (;cc<chns;cc++) {
sampl=**dma; (*dma)++;
sampl=(((sampl & 0xffff)<<16)|((sampl & 0xffff0000)>>16))^0x80008000;
- *data=sampl;
- data++;
+ comedi_buf_put_long( s->async, sampl );
}
sp+=cc<<1;
if (cc>=chans) {
if(sp>=devpriv->ai_n_scanlen) { // is end of one scan?
sp=0;
devpriv->ai_act_scan++;
- s->async->events|=COMEDI_CB_EOS;
- if (*sampls)
+ if (*sampls)
if (devpriv->ai_flags & TRIG_WAKE_EOS) {
comedi_event(dev,s,s->async->events);
s->async->events=0;
*bufs-=*bufs-(xx<<1);
*sampls-=*sampls-(yy<<1);
devpriv->ai_act_scanpos=sp;
- s->async->cur_chan=cc;
return 0;
}
sampl=inw(dev->iobase+PCI9118_AD_DATA);
if (devpriv->ai16bits) {
- *(sampl_t *)(s->async->data+s->async->buf_int_ptr)=sampl^0x8000;
+ comedi_buf_put( s->async, sampl ^ 0x8000 );
} else {
#ifdef PCI9118_PARANOIDCHECK
if ((sampl & 0x000f)!=devpriv->chanlist[s->async->cur_chan]) { // data dropout!
return;
}
#endif
- *(sampl_t *)(s->async->data+s->async->buf_int_ptr)=(sampl>>4) & 0x0fff;
+ comedi_buf_put( s->async, ( sampl >> 4 ) & 0x0fff );
}
- s->async->buf_int_ptr+=sizeof(sampl_t);
- s->async->buf_int_count+=sizeof(sampl_t);
-
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_scanlen) { /* one scan done */
- s->async->cur_chan=0;
+ if (s->async->cur_chan == 0) { /* one scan done */
devpriv->ai_act_scan++;
- s->async->events |= COMEDI_CB_EOS;
if (!(devpriv->ai_neverending))
if (devpriv->ai_act_scan>=devpriv->ai_scans) { /* all data sampled */
pci9118_ai_cancel(dev,s);
s->async->events |= COMEDI_CB_EOA;
}
}
-
- if (s->async->buf_int_ptr >= s->async->data_len) { /* buffer rollover */
- s->async->buf_int_ptr = 0;
- s->async->events |= COMEDI_CB_EOBUF;
- }
- if (s->async->events)
+ if (s->async->events)
comedi_event(dev,s,s->async->events);
}
-/*
+/*
==============================================================================
*/
-static void interrupt_pci9118_ai_dma(comedi_device *dev,comedi_subdevice *s,
- unsigned short int_adstat, unsigned int int_amcc, unsigned short int_daq)
+static void interrupt_pci9118_ai_dma(comedi_device *dev,comedi_subdevice *s,
+ unsigned short int_adstat, unsigned int int_amcc, unsigned short int_daq)
{
lsampl_t *ptr;
unsigned int next_dma_buf, samplesinbuf, sampls, m;
-
+
s->async->events=0;
if (int_amcc&MASTER_ABORT_INT) {
if (int_adstat & devpriv->ai_maskerr)
// if (int_adstat & 0x106)
- if (pci9118_decode_error_status(dev,s,int_adstat))
+ if (pci9118_decode_error_status(dev,s,int_adstat))
return;
samplesinbuf=devpriv->dmabuf_use_size[devpriv->dma_actbuf]>>1; // number of received real samples
// DPRINTK("dma_actbuf=%d\n",devpriv->dma_actbuf);
-
+
if (devpriv->dma_doublebuf) { // switch DMA buffers if is used double buffering
next_dma_buf=1-devpriv->dma_actbuf;
outl(devpriv->dmabuf_hw[next_dma_buf], devpriv->iobase_a+AMCC_OP_REG_MWAR);
outl(devpriv->dmabuf_use_size[next_dma_buf], devpriv->iobase_a+AMCC_OP_REG_MWTC);
devpriv->dmabuf_used_size[next_dma_buf]=devpriv->dmabuf_use_size[next_dma_buf];
- if (devpriv->ai_do==4)
- interrupt_pci9118_ai_mode4_switch(dev);
+ if (devpriv->ai_do==4)
+ interrupt_pci9118_ai_mode4_switch(dev);
}
ptr=(lsampl_t *)devpriv->dmabuf_virt[devpriv->dma_actbuf];
while (samplesinbuf) {
- m=(devpriv->ai_data_len-s->async->buf_int_ptr)>>1; // how many samples is to end of buffer
+ m = devpriv->ai_data_len >> 1; // how many samples is to end of buffer
// DPRINTK("samps=%d m=%d %d %d\n",samplesinbuf,m,s->async->buf_int_count,s->async->buf_int_ptr);
sampls=m;
- if (devpriv->dma_ai_read_block(dev, s, &ptr,
- ((void *)(devpriv->ai_data))+s->async->buf_int_ptr,
+ if (devpriv->dma_ai_read_block(dev, s, &ptr,
&sampls, &samplesinbuf))
return; // Uiii, error
m=m-sampls; // m= how many samples was transfered
- s->async->buf_int_count+=m<<1;
- s->async->buf_int_ptr+=m<<1;
- s->async->events|=COMEDI_CB_BLOCK;
- if (s->async->buf_int_ptr>=devpriv->ai_data_len) { // output buffer filled
-// DPRINTK("EOBUF scans=%d\n",devpriv->ai_act_scan);
- s->async->events|=COMEDI_CB_EOBUF;
- s->async->buf_int_ptr=0;
- comedi_event(dev,s,s->async->events);
- s->async->events=0;
- }
}
// DPRINTK("YYY\n");
-
+
if (!devpriv->ai_neverending)
if ( devpriv->ai_act_scan>=devpriv->ai_scans ) { /* all data sampled */
pci9118_ai_cancel(dev,s);
s->async->events|=COMEDI_CB_EOA;
}
-
+
if (devpriv->dma_doublebuf) { // switch dma buffers
- devpriv->dma_actbuf=1-devpriv->dma_actbuf;
+ devpriv->dma_actbuf=1-devpriv->dma_actbuf;
} else { // restart DMA if is not used double buffering
outl(devpriv->dmabuf_hw[0], devpriv->iobase_a+AMCC_OP_REG_MWAR);
outl(devpriv->dmabuf_use_size[0], devpriv->iobase_a+AMCC_OP_REG_MWTC);
switch (devpriv->usedma) {
case 2: // 32 bit DMA mode
if (devpriv->ai16bits) { // select interrupt function
- devpriv->dma_ai_read_block=(void *)move_block_from_dma_16bit_32b;
+ devpriv->dma_ai_read_block=move_block_from_dma_16bit_32b;
} else {
- devpriv->dma_ai_read_block=(void *)move_block_from_dma_12bit_32b;
+ devpriv->dma_ai_read_block=move_block_from_dma_12bit_32b;
}
outl(0x00000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR);
break;
case 1: // 16 bit DMA mode
if (devpriv->ai16bits) { // select interrupt function
- devpriv->dma_ai_read_block=(void *)move_block_from_dma_16bit_16b;
+ devpriv->dma_ai_read_block=move_block_from_dma_16bit_16b;
} else {
- devpriv->dma_ai_read_block=(void *)move_block_from_dma_12bit_16b;
+ devpriv->dma_ai_read_block=move_block_from_dma_12bit_16b;
}
outl(0x02000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR);
break;
return;
}
- *(sampl_t *)(s->async->data+s->async->buf_int_ptr)=0;
- s->async->buf_int_ptr+=sizeof(sampl_t);
- s->async->buf_int_count+=sizeof(sampl_t);
- if(s->async->buf_int_ptr>=s->async->data_len){
- s->async->buf_int_ptr=0;
- s->async->events |= COMEDI_CB_EOBUF;
- }
- s->async->events |= COMEDI_CB_EOS;
+ comedi_buf_put( s->async, 0 );
comedi_event(dev,s,s->async->events);
}
das16m1_handler(dev, status);
comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
- return s->async->buf_int_count - s->async->buf_user_count;
+ return s->async->buf_write_count - s->async->buf_read_count;
}
static void das16m1_interrupt(int irq, void *d, struct pt_regs *regs)
das1800_ai_handler(dev);
comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
- return s->async->buf_int_count - s->async->buf_user_count;
+ return s->async->buf_write_count - s->async->buf_read_count;
}
static void das1800_interrupt(int irq, void *d, struct pt_regs *regs)
das6402_ai_fifo_dregs(dev,s);
- if(s->async->buf_int_count >= devpriv->ai_bytes_to_read){
+ if(s->async->buf_write_count >= devpriv->ai_bytes_to_read){
outw_p(SCANL,dev->iobase+2); /* clears the fifo */
outb(0x07,dev->iobase+8); /* clears all flip-flops */
#ifdef DEBUG
}
}
-static void copy_to_buf(comedi_device *dev,comedi_subdevice *s,void *buf,unsigned int n_bytes)
-{
- unsigned int n;
-
- n=n_bytes;
- if(s->async->buf_int_ptr+n >= s->async->data_len){
- n=s->async->data_len-s->async->buf_int_ptr;
- memcpy(s->async->data+s->async->buf_int_ptr,buf,n);
- buf+=n;
- s->async->buf_int_count+=n;
- s->async->buf_int_ptr=0;
-
- n=n_bytes-n;
- }
- memcpy(s->async->data+s->async->buf_int_ptr,buf,n);
- buf+=n;
- s->async->buf_int_count+=n;
- s->async->buf_int_ptr+=n;
-}
-
-static int copy_from_buf(comedi_device *dev,comedi_subdevice *s,void *buf,unsigned int n_bytes)
-{
- unsigned int n,m;
-
- n=s->async->buf_int_count-s->async->buf_user_count;
- if(n==0)return 0;
- if(n>n_bytes)
- n=n_bytes;
-
- n_bytes=n;
- if(s->async->buf_int_ptr+n >= s->async->data_len){
- m=s->async->data_len-s->async->buf_int_ptr;
- memcpy(buf,s->async->data+s->async->buf_int_ptr,m);
- buf+=m;
- s->async->buf_int_count+=m;
- s->async->buf_int_ptr=0;
-
- n-=m;
- }
- memcpy(buf,s->async->data+s->async->buf_int_ptr,n);
- s->async->buf_int_count+=n;
- s->async->buf_int_ptr+=n;
-
- return n_bytes;
-}
-
-
static void dt282x_ao_dma_interrupt(comedi_device * dev)
{
void *ptr;
devpriv->current_dma_chan=1-i;
- size=copy_from_buf(dev,s,ptr,devpriv->dma_maxsize*2);
- if(!size){
+ size = comedi_buf_get_array( s->async, ptr, devpriv->dma_maxsize );
+ if( size < 0){
printk("dt282x: AO underrun\n");
dt282x_ao_cancel(dev,s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
comedi_event(dev,s,s->async->events);
return;
}
- prep_ao_dma(dev,i,size/2);
+ prep_ao_dma(dev,i,size);
enable_dma(devpriv->dma[i].chan);
- s->async->events |= COMEDI_CB_BLOCK;
comedi_event(dev,s,s->async->events);
return;
}
devpriv->current_dma_chan=1-i;
dt282x_cleanup_buffer(dev,ptr,size);
- copy_to_buf(dev,s,ptr,size*2);
+ comedi_buf_put_array( s->async, ptr, size );
devpriv->nread-=size;
if(devpriv->nread<0){
comedi_event(dev,s,s->async->events);
return;
- }else{
- s->async->events |= COMEDI_CB_BLOCK;
}
#if 1
if(devpriv->ad_2scomp){
data^=1<<(boardtype.adbits-1);
}
- *(sampl_t *)(s->async->data+s->async->buf_int_ptr)=data;
- s->async->buf_int_ptr+=sizeof(sampl_t);
- s->async->buf_int_count+=sizeof(sampl_t);
- if(s->async->buf_int_ptr>=s->async->data_len){
- s->async->buf_int_ptr = 0;
- s->async->events |= COMEDI_CB_EOBUF;
- }
+ comedi_buf_put( s->async, data );
devpriv->nread--;
if(!devpriv->nread){
if(x!=0)return -EINVAL;
- size=copy_from_buf(dev,s,devpriv->dma[0].buf,devpriv->dma_maxsize*2);
- prep_ao_dma(dev,0,size/2);
+ size=comedi_buf_get_array( s->async, devpriv->dma[0].buf, devpriv->dma_maxsize);
+ if( size < 0 ) return size;
+
+ prep_ao_dma(dev,0,size);
enable_dma(devpriv->dma[0].chan);
- size=copy_from_buf(dev,s,devpriv->dma[1].buf,devpriv->dma_maxsize*2);
- prep_ao_dma(dev,1,size/2);
+ size=comedi_buf_get_array( s->async, devpriv->dma[1].buf, devpriv->dma_maxsize);
+ prep_ao_dma(dev,1,size);
enable_dma(devpriv->dma[1].chan);
update_supcsr(DT2821_STRIG);
handle_a_interrupt(dev,a_status,m0_status);
}
if(b_status&Interrupt_B_St)handle_b_interrupt(dev,b_status);
-
+
win_restore(wsave);
}
writel(CHOR_CLRLC, mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(mite->chan));
- count = mite_bytes_transferred(mite, 0) - async->buf_int_count;
+ count = mite_bytes_transferred(mite, 0) - async->buf_write_count;
if(count < 0 || count > 100000){
printk("BUG: too many samples in interrupt (%d)\n",count);
return;
}
- async->buf_int_count += count;
+ async->buf_write_count += count;
if(async->cmd.flags & CMDF_RAWDATA){
/*
* Don't munge the data, just update the user's status
* variables
*/
- async->buf_int_ptr += count;
- if(async->buf_int_ptr >= async->prealloc_bufsz)
- async->buf_int_ptr -= async->prealloc_bufsz;
+ async->buf_write_ptr += count;
+ if(async->buf_write_ptr >= async->prealloc_bufsz)
+ async->buf_write_ptr -= async->prealloc_bufsz;
}else{
/*
* Munge the ADC data to change its format from two's
* complement to unsigned int. This is slow but makes
* it more compatible with other cards.
*/
- if(async->buf_int_ptr + count >= async->prealloc_bufsz){
+ if(async->buf_write_ptr + count >= async->prealloc_bufsz){
ni_munge(dev,s,
- async->prealloc_buf + async->buf_int_ptr,
+ async->prealloc_buf + async->buf_write_ptr,
async->prealloc_buf + async->prealloc_bufsz);
- async->buf_int_ptr += count;
- async->buf_int_ptr -= async->prealloc_bufsz;
+ async->buf_write_ptr += count;
+ async->buf_write_ptr -= async->prealloc_bufsz;
ni_munge(dev,s,
async->prealloc_buf,
- async->prealloc_buf + async->buf_int_ptr);
+ async->prealloc_buf + async->buf_write_ptr);
}else{
ni_munge(dev,s,
- async->prealloc_buf + async->buf_int_ptr,
- async->prealloc_buf + async->buf_int_ptr + count);
- async->buf_int_ptr += count;
+ async->prealloc_buf + async->buf_write_ptr,
+ async->prealloc_buf + async->buf_write_ptr + count);
+ async->buf_write_ptr += count;
}
}
s->async->events |= COMEDI_CB_BLOCK;
comedi_subdevice *s = dev->subdevices+0;
comedi_async *async = s->async;
struct mite_struct *mite = devpriv->mite;
-
+
async->events |= COMEDI_CB_BLOCK;
MDPRINTK("mite_handle_interrupt: m_status=%08x\n",m_status);
//comedi_event(dev,s,s->async->events);
- return s->async->buf_int_count-s->async->buf_user_count;
+ return s->async->buf_write_count - s->async->buf_read_count;
#else
/* XXX we don't support this yet. */
return -EINVAL;
// increment channel index
async->cur_chan = (async->cur_chan + n) % async->cmd.chanlist_len;
// increment async buf_int_count and buf_int_ptr
- async->buf_int_count += n * sizeof(sampl_t);
- async->buf_int_ptr += n * sizeof(sampl_t);
+ async->buf_read_count += n * sizeof(sampl_t);
+ async->buf_read_ptr += n * sizeof(sampl_t);
// check if we have reached end of buffer
- if(async->buf_int_ptr >= async->data_len)
+ if(async->buf_read_ptr >= async->data_len)
{
- async->buf_int_ptr -= async->data_len;
+ async->buf_read_ptr -= async->data_len;
// this shouldn't ever happen
- if(async->buf_int_ptr >= async->data_len)
+ if(async->buf_read_ptr >= async->data_len)
comedi_error(dev, "ao bug!");
}
}
{
int n,m;
- n=(s->async->buf_int_count-s->async->buf_user_count)/sizeof(sampl_t);
+ n=(s->async->buf_read_count - s->async->buf_write_count) / sizeof(sampl_t);
if(n==0)return 0;
if(n>boardtype.ao_fifo_depth/2)
n=boardtype.ao_fifo_depth/2;
- if(s->async->buf_int_ptr+n*sizeof(sampl_t)>s->async->data_len){
- m=(s->async->data_len-s->async->buf_int_ptr)/sizeof(sampl_t);
- ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,m);
+ if(s->async->buf_read_ptr+n*sizeof(sampl_t)>s->async->data_len){
+ m=(s->async->data_len-s->async->buf_read_ptr)/sizeof(sampl_t);
+ ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_read_ptr,m);
n-=m;
}
- ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,n);
+ ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_read_ptr,n);
s->async->events |= COMEDI_CB_BLOCK;
win_out(0,DAC_FIFO_Clear);
/* load some data */
- n=(s->async->buf_user_count-s->async->buf_int_count)/sizeof(sampl_t);
+ n=(s->async->buf_write_count-s->async->buf_read_count)/sizeof(sampl_t);
if(n<0)return 0;
if(n>boardtype.ao_fifo_depth)
n=boardtype.ao_fifo_depth;
- ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,n);
+ ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_read_ptr,n);
return n;
}
status = readb(dev->iobase+Interrupt_And_Window_Status);
flags = readb(dev->iobase+Group_1_Flags);
m_status = readl(mite->mite_io_addr + MITE_CHSR + CHAN_OFFSET(1));
-
+
//interrupcions parasites
if(dev->attached == 0){
comedi_error(dev,"premature interrupt");
- async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA;
}
-
+
DPRINTK("ni_pcidio_interrupt: status=0x%02x,flags=0x%02x,m_status=0x%08x\n",
status,flags,m_status);
ni_pcidio_print_flags(flags);
/* XXX need to byteswap */
- async->buf_int_count += count;
- async->buf_int_ptr += count;
- if(async->buf_int_ptr >= async->data_len){
- async->buf_int_ptr -= async->data_len;
+ async->buf_write_count += count;
+ async->buf_write_ptr += count;
+ if(async->buf_write_ptr >= async->data_len){
+ async->buf_write_ptr -= async->data_len;
}
mite->current_link++;
if(mite->current_link >= mite->n_links){
}
async->events |= COMEDI_CB_BLOCK;
}
-
+
while(status&DataLeft){
work++;
if(work>20){
}
flags &= IntEn;
-
+
if(flags & TransferReady){
//DPRINTK("TransferReady\n");
while(flags & TransferReady){
DPRINTK("CountExpired\n");
writeb(ClearExpired,dev->iobase+Group_1_Second_Clear);
async->events |= COMEDI_CB_EOA;
-
+
writeb(0x00,dev->iobase+OpMode);
writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
#ifdef USE_DMA
}else{
/* XXX */
}
-
+
#ifdef USE_DMA
writeb(0x05,dev->iobase+DMA_Line_Control);
writeb(0x30,dev->iobase+Group_1_First_Clear);
comedi_spin_unlock_irqrestore(&dev->spinlock,flags);
- return s->async->buf_int_count-s->async->buf_user_count;
+ return s->async->buf_write_count-s->async->buf_read_count;
}
/*
unsigned int top1,top2,i;
if (!devpriv->dma) return 0; // poll is valid only for DMA transfer
-
+
comedi_spin_lock_irqsave(&dev->spinlock, flags);
for (i=0; i<20; i++) {
transfer_from_dma_buf(dev, s, (sampl_t*)devpriv->dmabuf[devpriv->next_dma_buf],
devpriv->ai_poll_ptr, top2);
-
+
devpriv->ai_poll_ptr = top1; // new buffer position
comedi_spin_unlock_irqrestore(&dev->spinlock,flags);
- return s->async->buf_int_count - s->async->buf_user_count;
+ return s->async->buf_write_count - s->async->buf_read_count;
}
static int rtd_ai_poll (comedi_device *dev,comedi_subdevice *s)
{
/* TODO: This needs to mask interrupts, read_dregs, and then re-enable */
- return s->async->buf_int_count - s->async->buf_user_count;
+ return s->async->buf_write_count - s->async->buf_read_count;
}
/*
async = s->async;
if(async == NULL) return 0;
- return async->buf_int_count;
+ return async->buf_write_count;
}
/*
comedi_async *async;
async = s->async;
- async->buf_user_count = buf_user_count;
+ async->buf_read_count = buf_user_count;
return 0;
}
char *comedi_strerror(int err)
{
return "unknown error";
-}
+}
int comedi_fileno(comedi_t *d)
{
return dev->minor;
}
+static void init_async_buf( comedi_async *async )
+{
+ async->buf_read_count = 0;
+ async->buf_write_count = 0;
+ async->buf_dirty_count = 0;
+ async->buf_read_ptr = 0;
+ async->buf_write_ptr = 0;
+}
+
int comedi_command(comedi_t *d,comedi_cmd *cmd)
{
comedi_device *dev = (comedi_device *)d;
s->subdev_flags |= SDF_RUNNING;
- async->buf_user_ptr=0;
- async->buf_user_count=0;
- async->buf_int_ptr=0;
- async->buf_int_count=0;
+ init_async_buf( async );
async->data = cmd->data;
async->data_len = cmd->data_len;
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <asm/uaccess.h>
#include <linux/comedi.h>
unsigned int mmap_count; /* current number of mmaps of prealloc_buf */
/* To avoid races and provide reliable overrun detection, read / writes
- * to buffer should proceed as follows:
+ * to buffer should make use of the read_from_async_buffer() and
+ * write_to_async_buffer() functions and proceed
+ * as follows:
+ *
* Writing:
- * 1) if appropriate, check space in buffer, using either 'count' or 'ptr' members
- * ('count' members are more convenient).
- * 2) increment write count
- * 3) write data to buffer
- * 4) increment write ptr
+ * 1) if appropriate, check space in buffer, using read/write count members
+ * 2) call write_to_async_buffer()
* Reading:
- * 1) read data from buffer, using 'ptr' members to determine how much
- * 2) update the read ptr
- * 3) if appropriate, check for overrun using 'count' members
- * 4) increment read count
+ * 1) if appropriate, check how much data is in buffer, using read/write
+ * count members
+ * 2) call read_from_async_buffer()
+ * 3) if appropriate, check return value for buffer overrun
+ *
+ * Note: there should be exactly one reader and one writer
*/
- volatile unsigned int buf_int_ptr; /* buffer marker for interrupt */
- unsigned int buf_user_ptr; /* buffer marker for read() and write() */
- volatile unsigned int buf_int_count; /* byte count for interrupt */
- unsigned int buf_user_count; /* byte count for read() and write() */
+ unsigned int buf_write_ptr; /* buffer marker for writer */
+ unsigned int buf_read_ptr; /* buffer marker for reader */
+ volatile unsigned int buf_write_count; /* byte count for writer (write completed) */
+ volatile unsigned int buf_dirty_count; /* byte count for writer (write in progress) */
+ volatile unsigned int buf_read_count; /* byte count for reader */
unsigned int cur_chan; /* useless channel marker for interrupt */
void *data;
return 0;
}
-// writes a data point to comedi's buffer, used for input
-static inline void comedi_buf_put(comedi_async *async, sampl_t x)
+/* To avoid races and provide reliable overrun detection, read / writes
+* to buffer should proceed generally as follows:
+* Writing:
+* 1) if appropriate, check space in buffer, using read/write count members
+* 2) increment dirty count
+* 3) write data to buffer
+* 4) increment write count
+* 5) keep track of where to write with write ptr
+* Reading:
+* 1) read data from buffer, using read/write count members to determine how much
+* 3) if appropriate, check for overrun using read/dirty count members
+* 4) increment read count
+* 2) keep track of where to read with read ptr
+*
+* Note: there should be exactly one reader and one writer
+*/
+static inline int write_to_async_buffer( comedi_async *async, const void *array,
+ unsigned int num_bytes, unsigned int from_user_space )
{
- async->buf_int_count += sizeof(sampl_t);
- *(sampl_t *)(async->data + async->buf_int_ptr) = x;
- async->buf_int_ptr += sizeof(sampl_t);
- if(async->buf_int_ptr >= async->data_len){
- async->buf_int_ptr = 0;
- async->events |= COMEDI_CB_EOBUF;
- }
- if(++async->cur_chan >= async->cmd.chanlist_len){
- async->cur_chan = 0;
- async->events |= COMEDI_CB_EOS;
+ async->buf_dirty_count += num_bytes;
+ while( num_bytes )
+ {
+ unsigned int block_size;
+
+ block_size = num_bytes;
+ if( async->buf_write_ptr + block_size > async->data_len)
+ block_size = async->data_len - async->buf_write_ptr;
+
+ if( from_user_space )
+ {
+ if( copy_from_user( async->data + async->buf_write_ptr, array, block_size ) )
+ return -EFAULT;
+ }else
+ memcpy( async->data + async->buf_write_ptr, array, block_size );
+
+ array += block_size;
+ num_bytes -= block_size;
+ async->buf_write_count += block_size;
+ async->buf_write_ptr += block_size;
+ if( async->buf_write_ptr == async->data_len )
+ {
+ async->buf_write_ptr = 0;
+ }
}
- async->events |= COMEDI_CB_BLOCK;
+
+ return 0;
}
-/* Writes an array of data points to comedi's buffer, used for input.
- * Can be more efficient than putting comedi_buf_put() in a loop. */
-static inline void comedi_buf_put_array(comedi_async *async, sampl_t* array, unsigned int length)
+static inline int read_from_async_buffer( comedi_async *async, void *destination,
+ unsigned int num_bytes, unsigned int from_user_space )
{
- unsigned int num_bytes;
- unsigned int xfer_count = 0;
+ unsigned int bytes_available = async->buf_write_count - async->buf_read_count;
+ unsigned int remaining = bytes_available;
+
+ if( bytes_available == 0 ) return -EAGAIN;
- while((num_bytes = length * sizeof(sampl_t) - xfer_count))
+ while( remaining )
{
- async->buf_int_count += num_bytes;
- if( async->buf_int_ptr + num_bytes > async->data_len)
- num_bytes = async->data_len - async->buf_int_ptr;
+ unsigned int block_size;
- memcpy(async->data + async->buf_int_ptr + xfer_count, array, num_bytes);
+ block_size = remaining;
+ if( async->buf_read_ptr + block_size > async->data_len )
+ block_size = async->data_len - async->buf_read_ptr;
- async->buf_int_ptr += num_bytes;
- if(async->buf_int_ptr >= async->data_len)
+ if( from_user_space )
{
- async->buf_int_ptr %= async->data_len;
- async->events |= COMEDI_CB_EOBUF;
- }
- async->cur_chan += num_bytes / sizeof(sampl_t);
- if(async->cur_chan >= async->cmd.chanlist_len)
+ if( copy_to_user( destination, async->data + async->buf_read_ptr, block_size ) )
+ return -EFAULT;
+ }else
+ memcpy( destination, async->data + async->buf_read_ptr, block_size );
+
+ destination += block_size;
+ remaining -= block_size;
+ async->buf_read_ptr += block_size;
+ if( async->buf_read_ptr == async->data_len )
{
- async->cur_chan %= async->cmd.chanlist_len;
- async->events |= COMEDI_CB_EOS;
+ async->buf_read_ptr = 0;
}
- xfer_count += num_bytes;
+ }
+ // check if buffer has overrun
+ if( async->buf_dirty_count - async->buf_read_count > async->data_len )
+ return -EIO;
+ async->buf_read_count += bytes_available;
+
+ return bytes_available - remaining;
+}
+
+/* Writes an array of data points to comedi's buffer, used for input.
+ * Can be more efficient than putting comedi_buf_put() in a loop. */
+static inline void __comedi_buf_put_array(comedi_async *async, void* array,
+ unsigned int num_bytes, unsigned int bytes_per_sample )
+{
+ if( async->buf_write_ptr + num_bytes >= async->data_len )
+ {
+ async->events |= COMEDI_CB_EOBUF;
+ }
+
+ write_to_async_buffer( async, array, num_bytes, 0 );
+
+ async->cur_chan += num_bytes / bytes_per_sample;
+ if( async->cur_chan >= async->cmd.chanlist_len )
+ {
+ async->cur_chan %= async->cmd.chanlist_len;
+ async->events |= COMEDI_CB_EOS;
}
async->events |= COMEDI_CB_BLOCK;
}
+static inline void comedi_buf_put_array(comedi_async *async, sampl_t *array,
+ unsigned int num_samples )
+{
+ __comedi_buf_put_array( async, array, num_samples * sizeof( sampl_t ), sizeof( sampl_t ) );
+}
+
+static inline void comedi_buf_put_long_array(comedi_async *async, lsampl_t *array,
+ unsigned int num_samples )
+{
+ __comedi_buf_put_array( async, array, num_samples * sizeof( lsampl_t ), sizeof( lsampl_t ) );
+}
+
+// writes a data point to comedi's buffer, used for input
+static inline void comedi_buf_put(comedi_async *async, sampl_t x)
+{
+ comedi_buf_put_array( async, &x, 1 );
+}
+
+// writes a long data point to comedi's buffer, used for input
+static inline void comedi_buf_put_long(comedi_async *async, lsampl_t x)
+{
+ comedi_buf_put_long_array( async, &x, 1 );
+}
+
/* Reads a data point from comedi's buffer, used for output.
* returns negative value on error. */
-static inline int comedi_buf_get(comedi_async *async, sampl_t *x)
+static inline int comedi_buf_get_array(comedi_async *async, sampl_t *array, unsigned int num_samples)
{
- if(async->buf_int_count == async->buf_user_count)
- return -EAGAIN;
+ unsigned int num_bytes = num_samples * sizeof( sampl_t );
+ int retval;
+ unsigned int read_ptr = async->buf_read_ptr;
- *x = *(sampl_t *)(async->data + async->buf_int_ptr);
- async->buf_int_ptr += sizeof(sampl_t);
- if(async->buf_int_ptr >= async->data_len){
- async->buf_int_ptr = 0;
+ retval = read_from_async_buffer( async, array, num_bytes, 0 );
+
+ if( retval < 0 )
+ {
+ async->events |= COMEDI_CB_ERROR;
+ return retval;
+ }
+
+ num_bytes = retval;
+ num_samples = retval / sizeof( sampl_t );
+
+ if( read_ptr + num_bytes >= async->data_len)
+ {
async->events |= COMEDI_CB_EOBUF;
}
- if(++async->cur_chan >= async->cmd.chanlist_len){
- async->cur_chan = 0;
+
+ async->cur_chan += num_samples;
+ if( async->cur_chan >= async->cmd.chanlist_len)
+ {
+ async->cur_chan %= async->cmd.chanlist_len;
async->events |= COMEDI_CB_EOS;
}
- async->buf_int_count += sizeof(sampl_t);
async->events |= COMEDI_CB_BLOCK;
- return 0;
+ return retval / sizeof( sampl_t );
+}
+
+/* Reads a data point from comedi's buffer, used for output.
+ * returns negative value on error. */
+static inline int comedi_buf_get(comedi_async *async, sampl_t *x)
+{
+ return comedi_buf_get_array( async, x, 1);
}