dep_tristate 'Real-time command emulator (timer)' CONFIG_COMEDI_RT_TIMER $CONFIG_COMEDI
fi
+define_bool CONFIG_COMEDI_FC m
init_async_buf( async );
- async->cur_chan = 0;
-
async->data = async->prealloc_buf;
async->data_len=async->prealloc_bufsz;
async->buf_write_ptr = 0;
async->buf_read_ptr = 0;
+
+ async->cur_chan = 0;
+ async->scan_progress = 0;
}
EXPORT_SYMBOL(comedi_buf_write_free);
EXPORT_SYMBOL(comedi_buf_write_alloc);
EXPORT_SYMBOL(comedi_buf_read_free);
-
+EXPORT_SYMBOL(comedi_buf_memcpy_to);
+EXPORT_SYMBOL(comedi_buf_memcpy_from);
#endif
}
}
+void comedi_buf_memcpy_to( comedi_async *async, unsigned int offset, const void *data,
+ unsigned int num_bytes )
+{
+ unsigned int write_ptr = async->buf_write_ptr + offset;
+
+ if( write_ptr > async->data_len )
+ write_ptr %= async->data_len;
+
+ while( num_bytes )
+ {
+ unsigned int block_size;
+
+ if( write_ptr + num_bytes > async->data_len)
+ block_size = async->data_len - write_ptr;
+ else
+ block_size = num_bytes;
+
+ memcpy( async->data + write_ptr, data, block_size );
+
+ data += block_size;
+ num_bytes -= block_size;
+
+ write_ptr = 0;
+ }
+}
+
+void comedi_buf_memcpy_from(comedi_async *async, unsigned int offset,
+ void *dest, unsigned int nbytes)
+{
+ void *src;
+ unsigned int read_ptr = async->buf_read_ptr + offset;
+
+ if( read_ptr > async->data_len )
+ read_ptr %= async->data_len;
+
+ while( nbytes )
+ {
+ unsigned int block_size;
+
+ src = async->data + read_ptr;
+
+ if( nbytes >= async->data_len - read_ptr )
+ block_size = async->data_len - read_ptr;
+ else
+ block_size = nbytes;
+
+ memcpy(dest, src, block_size );
+ nbytes -= block_size;
+ dest += block_size;
+ read_ptr = 0;
+ }
+}
+
unsigned int comedi_buf_read_n_available(comedi_async *async)
{
unsigned int read_end = async->buf_write_count;
void comedi_buf_copy_from(comedi_async *async, void *dest, int nbytes)
{
- void *src;
-
- src = async->prealloc_buf + async->buf_read_ptr;
- if(async->buf_read_ptr + nbytes >= async->prealloc_bufsz){
- memcpy(dest, src,
- async->prealloc_bufsz - async->buf_read_ptr - nbytes);
- nbytes -= async->prealloc_bufsz - async->buf_read_ptr;
- src = async->prealloc_buf;
- dest += async->prealloc_bufsz - async->buf_read_ptr;
- }
- memcpy(dest, src, nbytes);
+ comedi_buf_memcpy_from( async, 0, dest, nbytes );
}
-
-expsyms(mite.o 8255.o amcc_s5933.o)
+expsyms(mite.o 8255.o amcc_s5933.o comedi_fc.o)
select(CONFIG_COMEDI_8255 8255.o)
select(CONFIG_COMEDI_ADL_PCI9111 adl_pci9111.o)
select(CONFIG_COMEDI_CB_PCIDAS64 cb_pcidas64.o)
select(CONFIG_COMEDI_CB_PCIDDA cb_pcidda.o)
select(CONFIG_COMEDI_CB_PCIMDDA cb_pcimdda.o)
+select(CONFIG_COMEDI_FC comedi_fc.o)
select(CONFIG_COMEDI_CONTEC_PCI_DIO contec_pci_dio.o)
select(CONFIG_COMEDI_DAQBOARD2000 daqboard2000.o)
select(CONFIG_COMEDI_DAS08 das08.o)
#include "8253.h"
#include "8255.h"
#include "amcc_s5933.h"
+#include "comedi_fc.h"
#undef CB_PCIDAS_DEBUG // disable debugging code
//#define CB_PCIDAS_DEBUG // enable debugging code
// PCI vendor number of ComputerBoards/MeasurementComputing
#define PCI_VENDOR_ID_CB 0x1307
#define TIMER_BASE 100 // 10MHz master clock
+#define AI_BUFFER_SIZE 1024 // maximum fifo size of any supported board
+#define AO_BUFFER_SIZE 1024 // maximum fifo size of any supported board
#define NUM_CHANNELS_8800 8
#define NUM_CHANNELS_7376 1
#define NUM_CHANNELS_8402 2
volatile unsigned int adc_fifo_bits; // bits to write to interupt/adcfifo register
volatile unsigned int s5933_intcsr_bits; // bits to write to amcc s5933 interrupt control/status register
volatile unsigned int ao_control_bits; // bits to write to ao control and status register
+ sampl_t ai_buffer[ AI_BUFFER_SIZE ];
+ sampl_t ao_buffer[ AO_BUFFER_SIZE ];
// divisors of master clock for analog output pacing
unsigned int ao_divisor1;
unsigned int ao_divisor2;
static int cb_pcidas_ao_inttrig(comedi_device *dev, comedi_subdevice *s, unsigned int trig_num)
{
- unsigned int i, num_points = thisboard->fifo_size;
- sampl_t d;
+ unsigned int num_bytes, num_points = thisboard->fifo_size;
comedi_async *async = s->async;
comedi_cmd *cmd = &s->async->cmd;
return -EINVAL;
// load up fifo
- if(cmd->stop_src == TRIG_COUNT &&
- devpriv->ao_count < num_points)
+ if( cmd->stop_src == TRIG_COUNT &&
+ devpriv->ao_count < num_points
+ )
num_points = devpriv->ao_count;
-
- // write data to board's fifo
- for(i = 0; i < num_points; i++) {
- /* XXX check return value */
- comedi_buf_get(async, &d);
- outw(devpriv->ao_registers + DACDATA, d);
- }
- if(cmd->stop_src == TRIG_COUNT) {
- devpriv->ao_count -= i;
+
+ num_bytes = cfc_read_array_from_buffer( s, devpriv->ao_buffer,
+ num_points * sizeof( sampl_t ) );
+ num_points = num_bytes / sizeof( sampl_t );
+
+ if(cmd->stop_src == TRIG_COUNT)
+ {
+ devpriv->ao_count -= num_points;
}
+ // write data to board's fifo
+ outsw( devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes );
// enable dac half-full and empty interrupts
devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
// if fifo half-full
if(status & ADHFI)
{
- int i;
-
// read data
num_samples = half_fifo;
if(async->cmd.stop_src == TRIG_COUNT &&
{
num_samples = devpriv->count;
}
- for(i=0;i<num_samples;i++){
- comedi_buf_put(async, inw(devpriv->adc_fifo + ADCDATA));
- }
+ insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer, num_samples);
+ cfc_write_array_to_buffer( s, devpriv->ai_buffer, num_samples * sizeof( sampl_t ) );
devpriv->count -= num_samples;
if(async->cmd.stop_src == TRIG_COUNT &&
devpriv->count == 0)
// break if fifo is empty
if((ADNE & inw(devpriv->control_status + INT_ADCFIFO)) == 0)
break;
- comedi_buf_put(async, inw(devpriv->adc_fifo + ADCDATA));
+ cfc_write_to_buffer( s, inw( devpriv->adc_fifo ) );
if(async->cmd.stop_src == TRIG_COUNT &&
--devpriv->count == 0)
{ /* end of acquisition */
comedi_async *async = s->async;
comedi_cmd *cmd = &async->cmd;
unsigned int half_fifo = thisboard->fifo_size / 2;
- unsigned int num_points, i;
+ unsigned int num_points;
async->events = 0;
}
}else if(status & DAHFI)
{
- sampl_t d;
+ unsigned int num_bytes;
// figure out how many points we are writing to fifo
num_points = half_fifo;
if(cmd->stop_src == TRIG_COUNT &&
devpriv->ao_count < num_points)
num_points = devpriv->ao_count;
- // write data to board's fifo
- for(i = 0; i < num_points; i++)
- {
- comedi_buf_get(async, &d);
- outw(devpriv->ao_registers + DACDATA, d);
- }
+ num_bytes = cfc_read_array_from_buffer( s, devpriv->ao_buffer, num_points * sizeof( sampl_t ) );
+ num_points = num_bytes / sizeof( sampl_t );
+
if(async->cmd.stop_src == TRIG_COUNT)
{
- devpriv->ao_count -= i;
+ devpriv->ao_count -= num_points;
}
- async->events |= COMEDI_CB_BLOCK;
+ // write data to board's fifo
+ outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_points);
// clear half-full interrupt latch
outw(devpriv->adc_fifo_bits | DAHFI, devpriv->control_status + INT_ADCFIFO);
}
#include "8253.h"
#include "8255.h"
#include "plx9080.h"
+#include "comedi_fc.h"
#undef PCIDAS64_DEBUG // disable debugging code
//#define PCIDAS64_DEBUG // enable debugging code
for(i = 0; i < num_samples; i++)
{
- comedi_buf_put(async, readw(priv(dev)->main_iobase + ADC_FIFO_REG));
+ cfc_write_to_buffer( s, readw(priv(dev)->main_iobase + ADC_FIFO_REG));
}
} while (read_segment != write_segment);
for(i = 0; read_code != write_code && i < max_transfer; )
{
fifo_data = readl(priv(dev)->dio_counter_iobase + ADC_FIFO_REG);
- comedi_buf_put(async, fifo_data & 0xffff);
+ cfc_write_to_buffer( s, fifo_data & 0xffff);
i++;
if(i < max_transfer)
{
- comedi_buf_put(async, (fifo_data >> 16) & 0xffff);
+ cfc_write_to_buffer( s, (fifo_data >> 16) & 0xffff);
i++;
}
read_code = readw(priv(dev)->main_iobase + ADC_READ_PNTR_REG) & 0x7fff;
num_samples = priv(dev)->ai_count;
priv(dev)->ai_count -= num_samples;
}
- comedi_buf_put_array(async, priv(dev)->ai_buffer[priv(dev)->dma_index], num_samples);
+ cfc_write_array_to_buffer( dev->read_subdev,
+ priv(dev)->ai_buffer[ priv(dev)->dma_index ], num_samples * sizeof( sampl_t ) );
priv(dev)->dma_index = (priv(dev)->dma_index + 1) % DMA_RING_COUNT;
DEBUG_PRINT("next buffer addr 0x%lx\n", (unsigned long) priv(dev)->ai_buffer_phys_addr[priv(dev)->dma_index]);
--- /dev/null
+/*
+ cfc.c
+
+ This is a place for code driver writers wish to share between
+ two or more drivers. cfc is short
+ for comedi-frank-common.
+
+ Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ Copyright (C) 2002 Frank Mori Hess
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You 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 02139, USA.
+
+************************************************************************/
+
+#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 );
+}
+
+static inline unsigned int bytes_per_scan( comedi_subdevice *subd )
+{
+ return subd->async->cmd.chanlist_len * bytes_per_sample( subd );
+}
+
+static void increment_scan_progress( comedi_subdevice *subd, unsigned int num_bytes )
+{
+ comedi_async *async = subd->async;
+ unsigned int scan_length = bytes_per_scan( subd );
+
+ async->scan_progress += num_bytes;
+ if( async->scan_progress >= scan_length )
+ {
+ async->scan_progress %= scan_length;
+ async->events |= COMEDI_CB_EOS;
+ }
+}
+
+/* Writes an array of data points to comedi's buffer */
+unsigned int cfc_write_array_to_buffer( comedi_subdevice *subd, void *data,
+ unsigned int num_bytes )
+{
+ comedi_async *async = subd->async;
+ unsigned int retval;
+
+ retval = comedi_buf_write_alloc( async, num_bytes );
+ if( retval != num_bytes )
+ {
+ async->events |= COMEDI_CB_ERROR;
+ return 0;
+ }
+
+ comedi_buf_memcpy_to( async, 0, data, num_bytes);
+
+ comedi_buf_write_free( async, num_bytes );
+
+ increment_scan_progress( subd, num_bytes );
+
+ if( num_bytes ) async->events |= COMEDI_CB_BLOCK;
+
+ return num_bytes;
+}
+
+unsigned int cfc_read_array_from_buffer( comedi_subdevice *subd, void *data,
+ unsigned int num_bytes )
+{
+ comedi_async *async = subd->async;
+ unsigned int bytes_available;
+
+ bytes_available = comedi_buf_read_n_available( async );
+ if( bytes_available < num_bytes )
+ {
+ num_bytes = bytes_available;
+ }
+
+ comedi_buf_memcpy_from( async, 0, data, num_bytes);
+
+ comedi_buf_read_free( async, num_bytes );
+
+ increment_scan_progress( subd, num_bytes );
+
+ if( num_bytes ) async->events |= COMEDI_CB_BLOCK;
+
+ return num_bytes;
+}
+
+MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>");
+MODULE_DESCRIPTION("Shared functoins for Comedi low-level drivers");
+MODULE_LICENSE("GPL");
+
+static int __init comedi_fc_init_module(void)
+{
+ return 0;
+}
+static void __exit comedi_fc_cleanup_module(void)
+{
+}
+module_init(comedi_fc_init_module);
+module_exit(comedi_fc_cleanup_module);
+
+EXPORT_SYMBOL( cfc_write_array_to_buffer );
+EXPORT_SYMBOL( cfc_read_array_from_buffer );
--- /dev/null
+/*
+ cfc.h
+
+ This is a place for code driver writers wish to share between
+ two or more drivers.
+ If it ever grows beyond a couple inline functions, I'll make
+ a cfc.o module to go with this header file. cfc is short
+ for comedi-frank-common.
+
+ Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ Copyright (C) 2002 Frank Mori Hess
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You 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 02139, USA.
+
+************************************************************************/
+
+#include "linux/comedidev.h"
+
+/* Writes an array of data points to comedi's buffer */
+unsigned int cfc_write_array_to_buffer( comedi_subdevice *subd, void *data,
+ unsigned int num_bytes );
+
+inline unsigned int cfc_write_to_buffer( comedi_subdevice *subd, sampl_t data )
+{
+ return cfc_write_array_to_buffer( subd, &data, sizeof( data ) );
+};
+
+inline unsigned int cfc_write_long_to_buffer( comedi_subdevice *subd, lsampl_t data )
+{
+ return cfc_write_array_to_buffer( subd, &data, sizeof( data ) );
+};
+
+unsigned int cfc_read_array_from_buffer( comedi_subdevice *subd, void *data,
+ unsigned int num_bytes );
comedi_error(dev, "read error");
return -EIO;
}
- comedi_buf_put(s->async, data);
+ if( s->flags % SDF_LSAMPL )
+ cfc_write_long_to_buffer( s, data );
+ else
+ cfc_write_to_buffer( s, data );
return 0;
}
unsigned int index)
{
comedi_subdevice *s = dev->write_subdev;
- int ret;
+ unsigned int num_bytes;
sampl_t data;
+ lsampl_t long_data;
+
+ if( s->flags & SDF_LSAMPL )
+ {
+ num_bytes = cfc_read_array_from_buffer( s, &long_data, sizeof( long_data ) );
+ }else
+ num_bytes = cfc_read_array_from_buffer( s, &data, sizeof( data ) );
+ long_data = data;
+ }
- ret = comedi_buf_get(s->async, &data);
- if(ret < 0) {
+ if(num_bytes == 0)
+ {
comedi_error(dev, "buffer underrun");
return -EAGAIN;
}
CR_CHAN(cmd->chanlist[index]),
CR_RANGE(cmd->chanlist[index]),
CR_AREF(cmd->chanlist[index]),
- data);
+ long_data);
if(ret<0){
comedi_error(dev, "write error");
return -EIO;
comedi_error(dev, "read error");
return -EIO;
}
- comedi_buf_put(s->async, data);
+
+ if( s->flags % SDF_LSAMPL )
+ cfc_write_long_to_buffer( s, data );
+ else
+ cfc_write_to_buffer( s, data );
return 0;
}
#include <linux/init.h>
#include <linux/comedidev.h>
#include <asm/div64.h>
+#include "comedi_fc.h"
/* Board descriptions */
typedef struct waveform_board_struct{
{
for( j = 0; j < cmd->chanlist_len; j++)
{
- comedi_buf_put(async,
+ cfc_write_to_buffer( dev->read_subdev,
fake_waveform(dev, CR_CHAN(cmd->chanlist[j]), CR_RANGE(cmd->chanlist[j]),
devpriv->usec_current + i * devpriv->scan_period + j * devpriv->convert_period));
}
devpriv->usec_current += elapsed_time;
devpriv->usec_current %= devpriv->usec_period;
- async->events |= COMEDI_CB_BLOCK;
-
if((async->events & COMEDI_CB_EOA) == 0 && devpriv->timer_running)
mod_timer(&devpriv->timer, jiffies + 1);
else
gain)
[6] - analog output range lowest voltage in microvolts (optional)
[7] - analog output range highest voltage in microvolts (optional)
- [8] - use timer mode for DMA, needed e.g. for buggy DMA controller
- in NS CS5530A (Geode Companion). If set, also allows
+ [8] - use timer mode for DMA, needed e.g. for buggy DMA controller
+ in NS CS5530A (Geode Companion). If set, also allows
comedi_command() to be run without an irq.
Passing a zero for an option is the same as leaving it unspecified.
-Both a dma channel and an irq (or use of 'timer mode', option 8) are required
+Both a dma channel and an irq (or use of 'timer mode', option 8) are required
for timed or externally triggered conversions.
*/
/*
#include <asm/dma.h>
#include "8253.h"
#include "8255.h"
+#include "comedi_fc.h"
#undef DEBUG
//#define DEBUG
mod_timer(&devpriv->timer, jiffies + timer_period);
}
+static void munge_ai_data( comedi_device *dev, sampl_t *data, unsigned int num_points)
+{
+ unsigned int i;
+
+ if( thisboard->ai_nbits == 12)
+ {
+ for(i = 0; i < num_points; i++)
+ {
+ data[i] = ( data[i] >> 4 ) & 0xfff;
+ }
+ }
+}
+
static void das16_interrupt( comedi_device *dev )
{
- int i;
unsigned long flags;
comedi_subdevice *s = dev->read_subdev;
comedi_async *async;
comedi_cmd *cmd;
int num_points, num_bytes, residue;
- sampl_t dpnt;
unsigned int target_xfer;
if(dev->attached == 0)
async->events |= COMEDI_CB_EOA;
}
- for(i = 0; i < num_points; i++)
- {
- /* write data point to comedi buffer */
- dpnt = devpriv->dma_buffer[i];
- if(thisboard->ai_nbits == 12)
- dpnt = (dpnt >> 4) & 0xfff;
- comedi_buf_put(async, dpnt);
- devpriv->adc_count--;
- }
+ munge_ai_data( dev, devpriv->dma_buffer, num_points );
+ cfc_write_array_to_buffer( s, devpriv->dma_buffer, num_points * sizeof( sampl_t ) );
+ devpriv->adc_count -= num_points;
// figure out how many bytes for next transfer
target_xfer = devpriv->target_transfer_size;
#include <linux/delay.h>
#include "8255.h"
#include "8253.h"
+#include "comedi_fc.h"
#define DAS16M1_SIZE 16
#define DAS16M1_SIZE2 8
#define DAS16M1_AI 0 // 16-bit wide register
#define AI_CHAN(x) ((x) & 0xf)
-#define AI_DATA(x) (((x) >> 4) & 0xfff)
#define DAS16M1_CS 2
#define EXT_TRIG_BIT 0x1
#define OVRUN 0x20
* needed to keep track of whether new count has been loaded into
* counter yet (loaded by first sample conversion) */
u16 initial_hw_count;
+ sampl_t ai_buffer[ FIFO_SIZE ];
unsigned int do_bits; // saves status of digital output bits
unsigned int divisor1; // divides master clock to obtain conversion speed
unsigned int divisor2; // divides master clock to obtain conversion speed
COMEDI_INITCLEANUP(driver_das16m1);
+static inline sampl_t munge_sample( sampl_t data )
+{
+ return ( data >> 4 ) & 0xfff;
+}
+
static int das16m1_cmd_test(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd)
{
unsigned int err=0, tmp, i;
comedi_error(dev, "timeout");
return -ETIME;
}
- data[n] = AI_DATA(inw(dev->iobase));
+ data[n] = munge_sample( inw( dev->iobase ) );
}
return n;
spin_unlock(&dev->spinlock);
}
+static void munge_sample_array( sampl_t *array, unsigned int num_elements )
+{
+ unsigned int i;
+
+ for(i = 0; i < num_elements; i++)
+ {
+ array[i] = munge_sample( array[i] );
+ }
+}
+
static void das16m1_handler(comedi_device *dev, unsigned int status)
{
- int i;
comedi_subdevice *s;
comedi_async *async;
comedi_cmd *cmd;
// make sure we dont try to get too many points if fifo has overrun
if(num_samples > FIFO_SIZE)
num_samples = FIFO_SIZE;
- for(i = 0; i < num_samples; i++) {
- sampl_t d;
-
- d = inw(dev->iobase);
- /* XXX check return value */
- comedi_buf_put(async, AI_DATA(d));
- }
+ insw( dev->iobase, devpriv->ai_buffer, num_samples );
+ munge_sample_array( devpriv->ai_buffer, num_samples );
+ cfc_write_array_to_buffer( s, devpriv->ai_buffer, num_samples * sizeof( sampl_t ) );
devpriv->adc_count += num_samples;
if(cmd->stop_src == TRIG_COUNT)
#include <asm/dma.h>
#include <linux/comedidev.h>
#include "8253.h"
+#include "comedi_fc.h"
// misc. defines
#define DAS1800_SIZE 16 //uses 16 io addresses
-#define HALF_FIFO 512 // 1024 sample fifo
+#define FIFO_SIZE 1024 // 1024 sample fifo
#define TIMER_BASE 200 // 5 Mhz master clock
#define UNIPOLAR 0x4 // bit that determines whether input range is uni/bipolar
#define DMA_BUF_SIZE 0x1ff00 // size in bytes of dma buffers
static void das1800_ai_handler(comedi_device *dev);
static void das1800_handle_dma(comedi_device *dev, comedi_subdevice *s, unsigned int status);
static void das1800_flush_dma(comedi_device *dev, comedi_subdevice *s);
-static void das1800_flush_dma_channel(comedi_device *dev, comedi_subdevice *s, unsigned int channel, u16 *buffer);
+static void das1800_flush_dma_channel(comedi_device *dev, comedi_subdevice *s, unsigned int channel, uint16_t *buffer);
static void das1800_handle_fifo_half_full(comedi_device *dev, comedi_subdevice *s);
static void das1800_handle_fifo_not_empty(comedi_device *dev, comedi_subdevice *s);
static int das1800_ai_do_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd);
unsigned int dma0; /* dma channels used */
unsigned int dma1;
volatile unsigned int dma_current; /* dma channel currently in use */
- u16 *dma_buf0; /* pointers to dma buffers */
- u16 *dma_buf1;
- u16 *dma_current_buf; /* pointer to dma buffer currently being used */
+ uint16_t *ai_buf0; /* pointers to dma buffers */
+ uint16_t *ai_buf1;
+ uint16_t *dma_current_buf; /* pointer to dma buffer currently being used */
unsigned int dma_transfer_size; /* size of transfer currently used, in bytes */
int iobase2; /* secondary io address used for analog out on 'ao' boards */
short ao_update_bits; /* remembers the last write to the 'update' dac */
*/
COMEDI_INITCLEANUP(driver_das1800);
+int das1800_init_dma( comedi_device *dev, unsigned int dma0, unsigned int dma1 )
+{
+ unsigned long flags;
+
+ // need an irq to do dma
+ if( dev->irq && dma0 )
+ {
+ //encode dma0 and dma1 into 2 digit hexadecimal for switch
+ switch((dma0 & 0x7) | (dma1 << 4))
+ {
+ case 0x5: // dma0 == 5
+ devpriv->dma_bits |= DMA_CH5;
+ break;
+ case 0x6: // dma0 == 6
+ devpriv->dma_bits |= DMA_CH6;
+ break;
+ case 0x7: // dma0 == 7
+ devpriv->dma_bits |= DMA_CH7;
+ break;
+ case 0x65: // dma0 == 5, dma1 == 6
+ devpriv->dma_bits |= DMA_CH5_CH6;
+ break;
+ case 0x76: // dma0 == 6, dma1 == 7
+ devpriv->dma_bits |= DMA_CH6_CH7;
+ break;
+ case 0x57: // dma0 == 7, dma1 == 5
+ devpriv->dma_bits |= DMA_CH7_CH5;
+ break;
+ default:
+ printk(" only supports dma channels 5 through 7\n"
+ " Dual dma only allows the following combinations:\n"
+ " dma 5,6 / 6,7 / or 7,5\n");
+ return -EINVAL;
+ break;
+ }
+ if( request_dma( dma0, driver_das1800.driver_name ) )
+ {
+ printk( " failed to allocate dma channel %i\n", dma0 );
+ return -EINVAL;
+ }
+ devpriv->dma0 = dma0;
+ devpriv->dma_current = dma0;
+ if( dma1 )
+ {
+ if( request_dma( dma1, driver_das1800.driver_name ) )
+ {
+ printk( " failed to allocate dma channel %i\n", dma1 );
+ return -EINVAL;
+ }
+ devpriv->dma1 = dma1;
+ }
+ devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
+ if(devpriv->ai_buf0 == NULL)
+ return -ENOMEM;
+ devpriv->dma_current_buf = devpriv->ai_buf0;
+ if( dma1 )
+ {
+ devpriv->ai_buf1 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
+ if(devpriv->ai_buf1 == NULL)
+ return -ENOMEM;
+ }
+ flags = claim_dma_lock();
+ disable_dma(devpriv->dma0);
+ set_dma_mode(devpriv->dma0, DMA_MODE_READ);
+ if( dma1 )
+ {
+ disable_dma(devpriv->dma1);
+ set_dma_mode(devpriv->dma1, DMA_MODE_READ);
+ }
+ release_dma_lock(flags);
+ }
+ return 0;
+}
+
static int das1800_attach(comedi_device *dev, comedi_devconfig *it)
{
comedi_subdevice *s;
- unsigned long flags;
int iobase = it->options[0];
int irq = it->options[1];
int dma0 = it->options[2];
int dma1 = it->options[3];
int iobase2;
int board;
+ int retval;
/* allocate and initialize dev->private */
if(alloc_private(dev, sizeof(das1800_private)) < 0)
break;
}
- //dma stuff
- // need an irq to do dma
- if(irq)
+ retval = das1800_init_dma( dev, dma0, dma1 );
+ if( retval < 0 ) return retval;
+
+ if( devpriv->ai_buf0 == NULL )
{
- if(dma0)
- {
- //encode dma0 and dma1 into 2 digit hexadecimal for switch
- switch((dma0 & 0x7) | (dma1 << 4))
- {
- case 0x5: // dma0 == 5
- devpriv->dma_bits |= DMA_CH5;
- break;
- case 0x6: // dma0 == 6
- devpriv->dma_bits |= DMA_CH6;
- break;
- case 0x7: // dma0 == 7
- devpriv->dma_bits |= DMA_CH7;
- break;
- case 0x65: // dma0 == 5, dma1 == 6
- devpriv->dma_bits |= DMA_CH5_CH6;
- break;
- case 0x76: // dma0 == 6, dma1 == 7
- devpriv->dma_bits |= DMA_CH6_CH7;
- break;
- case 0x57: // dma0 == 7, dma1 == 5
- devpriv->dma_bits |= DMA_CH7_CH5;
- break;
- default:
- printk(" only supports dma channels 5 through 7\n"
- " Dual dma only allows the following combinations:\n"
- " dma 5,6 / 6,7 / or 7,5\n");
- return -EINVAL;
- break;
- }
- if(request_dma(dma0, driver_das1800.driver_name))
- {
- printk(" failed to allocate dma channel %i\n", dma0);
- return -EINVAL;
- }
- devpriv->dma0 = dma0;
- devpriv->dma_current = dma0;
- if(dma1)
- {
- if(request_dma(dma1, driver_das1800.driver_name))
- {
- printk(" failed to allocate dma channel %i\n", dma1);
- return -EINVAL;
- }
- devpriv->dma1 = dma1;
- }
- devpriv->dma_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
- if(devpriv->dma_buf0 == NULL)
- return -ENOMEM;
- devpriv->dma_current_buf = devpriv->dma_buf0;
- if(dma1)
- {
- devpriv->dma_buf1 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
- if(devpriv->dma_buf1 == NULL)
- return -ENOMEM;
- }
- flags = claim_dma_lock();
- disable_dma(devpriv->dma0);
- set_dma_mode(devpriv->dma0, DMA_MODE_READ);
- if(dma1)
- {
- disable_dma(devpriv->dma1);
- set_dma_mode(devpriv->dma1, DMA_MODE_READ);
- }
- release_dma_lock(flags);
- }
+ devpriv->ai_buf0 = kmalloc( FIFO_SIZE * sizeof( uint16_t ), GFP_KERNEL );
+ if(devpriv->ai_buf0 == NULL)
+ return -ENOMEM;
}
dev->n_subdevices = 4;
free_dma(devpriv->dma0);
if(devpriv->dma1)
free_dma(devpriv->dma1);
- if(devpriv->dma_buf0)
- kfree(devpriv->dma_buf0);
- if(devpriv->dma_buf1)
- kfree(devpriv->dma_buf1);
+ if(devpriv->ai_buf0)
+ kfree(devpriv->ai_buf0);
+ if(devpriv->ai_buf1)
+ kfree(devpriv->ai_buf1);
}
printk("comedi%d: %s: remove\n", dev->minor, driver_das1800.driver_name);
if(devpriv->dma_current == devpriv->dma0)
{
devpriv->dma_current = devpriv->dma1;
- devpriv->dma_current_buf = devpriv->dma_buf1;
+ devpriv->dma_current_buf = devpriv->ai_buf1;
}
else
{
devpriv->dma_current = devpriv->dma0;
- devpriv->dma_current_buf = devpriv->dma_buf0;
+ devpriv->dma_current_buf = devpriv->ai_buf0;
}
}
}
return;
}
+static inline uint16_t munge_bipolar_sample( const comedi_device *dev, uint16_t sample )
+{
+ sample += 1 << ( thisboard->resolution - 1 );
+ return sample;
+}
+
+static void munge_data( comedi_device *dev, uint16_t *array, unsigned int num_elements )
+{
+ unsigned int i;
+ int unipolar;
+
+ /* see if card is using a unipolar or bipolar range so we can munge data correctly */
+ unipolar = inb( dev->iobase + DAS1800_CONTROL_C ) & UB;
+
+ /* convert to unsigned type if we are in a bipolar mode */
+ if( !unipolar )
+ {
+ for( i = 0; i < num_elements; i++ )
+ {
+ array[i] = munge_bipolar_sample( dev, array[i] );
+ }
+ }
+}
+
/* Utility function used by das1800_flush_dma() and das1800_handle_dma().
* Assumes dma lock is held */
-static void das1800_flush_dma_channel(comedi_device *dev, comedi_subdevice *s, unsigned int channel, u16 *buffer)
+static void das1800_flush_dma_channel(comedi_device *dev, comedi_subdevice *s, unsigned int channel, uint16_t *buffer)
{
- unsigned int numPoints;
- int unipolar;
- int i;
- const int bytes_per_sample = 2;
+ unsigned int num_bytes, num_samples;
comedi_cmd *cmd = &s->async->cmd;
disable_dma(channel);
clear_dma_ff(channel);
// figure out how many points to read
- numPoints = (devpriv->dma_transfer_size - get_dma_residue(channel)) /
- bytes_per_sample;
- /* if we only need some of the points */
- if(cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints)
- numPoints = devpriv->count;
+ num_bytes = devpriv->dma_transfer_size - get_dma_residue( channel );
+ num_samples = num_bytes / sizeof( sampl_t );
- /* see if card is using a unipolar or bipolar range so we can munge data correctly */
- unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
+ /* if we only need some of the points */
+ if( cmd->stop_src == TRIG_COUNT && devpriv->count < num_samples )
+ num_samples = devpriv->count;
- // read data from dma buffer
- for( i = 0; i < numPoints; i++)
- {
- /* convert to unsigned type if we are in a bipolar mode */
- if(!unipolar);
- buffer[i] += 1 << (thisboard->resolution - 1);
- comedi_buf_put(s->async, buffer[i]);
- if(s->async->cmd.stop_src == TRIG_COUNT)
- devpriv->count--;
- }
+ munge_data( dev, buffer, num_samples );
+ cfc_write_array_to_buffer( s, buffer, num_bytes );
+ if(s->async->cmd.stop_src == TRIG_COUNT)
+ devpriv->count -= num_samples;
return;
}
if(devpriv->dma_current == devpriv->dma0)
{
devpriv->dma_current = devpriv->dma1;
- devpriv->dma_current_buf = devpriv->dma_buf1;
+ devpriv->dma_current_buf = devpriv->ai_buf1;
}
else
{
devpriv->dma_current = devpriv->dma0;
- devpriv->dma_current_buf = devpriv->dma_buf0;
+ devpriv->dma_current_buf = devpriv->ai_buf0;
}
das1800_flush_dma_channel(dev, s, devpriv->dma_current, devpriv->dma_current_buf);
}
static void das1800_handle_fifo_half_full(comedi_device *dev, comedi_subdevice *s)
{
- int i; /* loop index */
int numPoints = 0; /* number of points to read */
- u16 data[HALF_FIFO];
- int unipolar;
comedi_cmd *cmd = &s->async->cmd;
- unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
-
- numPoints = HALF_FIFO;
+ numPoints = FIFO_SIZE / 2;
/* if we only need some of the points */
if(cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints)
numPoints = devpriv->count;
- insw(dev->iobase + DAS1800_FIFO, data, numPoints);
- for( i = 0; i < numPoints; i++)
- {
- /* write data point to buffer */
- /* convert to unsigned type if we are in a bipolar mode */
- if(!unipolar);
- data[i] += 1 << (thisboard->resolution - 1);
- comedi_buf_put(s->async, data[i]);
- if(cmd->stop_src == TRIG_COUNT) devpriv->count--;
- }
+ insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, numPoints);
+ munge_data( dev, devpriv->ai_buf0, numPoints );
+ cfc_write_array_to_buffer( s, devpriv->ai_buf0, numPoints * sizeof( devpriv->ai_buf0[0] ) );
+ if( cmd->stop_src == TRIG_COUNT )
+ devpriv->count -= numPoints;
return;
}
unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB;
- while(inb(dev->iobase + DAS1800_STATUS) & FNE)
+ while( inb( dev->iobase + DAS1800_STATUS ) & FNE )
{
if(cmd->stop_src == TRIG_COUNT && devpriv->count == 0)
break;
- dpnt = inw(dev->iobase + DAS1800_FIFO);
+ dpnt = inw( dev->iobase + DAS1800_FIFO );
/* convert to unsigned type if we are in a bipolar mode */
if(!unipolar);
- dpnt += 1 << (thisboard->resolution - 1);
- comedi_buf_put(s->async, dpnt);
+ dpnt = munge_bipolar_sample( dev, dpnt );
+ cfc_write_to_buffer( s, dpnt );
if(cmd->stop_src == TRIG_COUNT) devpriv->count--;
}
/* clear flip-flop to make sure 2-byte registers for
* count and address get set correctly */
clear_dma_ff(devpriv->dma0);
- set_dma_addr(devpriv->dma0, virt_to_bus(devpriv->dma_buf0));
+ set_dma_addr(devpriv->dma0, virt_to_bus(devpriv->ai_buf0));
// set appropriate size of transfer
set_dma_count(devpriv->dma0, devpriv->dma_transfer_size);
devpriv->dma_current = devpriv->dma0;
- devpriv->dma_current_buf = devpriv->dma_buf0;
+ devpriv->dma_current_buf = devpriv->ai_buf0;
enable_dma(devpriv->dma0);
// set up dual dma if appropriate
if(dual_dma)
/* clear flip-flop to make sure 2-byte registers for
* count and address get set correctly */
clear_dma_ff(devpriv->dma1);
- set_dma_addr(devpriv->dma1, virt_to_bus(devpriv->dma_buf1));
+ set_dma_addr(devpriv->dma1, virt_to_bus(devpriv->ai_buf1));
// set appropriate size of transfer
set_dma_count(devpriv->dma1, devpriv->dma_transfer_size);
enable_dma(devpriv->dma1);
#include <asm/io.h>
#include <linux/comedidev.h>
#include "8253.h"
+#include "comedi_fc.h"
#define DAS800_SIZE 8
#define TIMER_BASE 1000
if(devpriv->count > 0 || devpriv->forever == 1)
{
/* write data point to buffer */
- comedi_buf_put(async, dataPoint);
+ cfc_write_to_buffer( s, dataPoint);
if(devpriv->count > 0) devpriv->count--;
}
}
/*
ni_at_a2150.c driver for National Instruments AT-A2150 boards
- Copyright (C) 2001 Frank Mori Hess <fmhess@uiuc.edu>
+ Copyright (C) 2001, 2002 Frank Mori Hess <fmhess@users.sourceforge.net>
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 2000 David A. Schleef <ds@schleef.org>
#include <asm/dma.h>
#include <linux/comedidev.h>
#include "8253.h"
+#include "comedi_fc.h"
#define A2150_SIZE 28
#define A2150_DMA_BUFFER_SIZE 0xff00 // size in bytes of dma buffer
dpnt = devpriv->dma_buffer[i];
// convert from 2's complement to unsigned coding
dpnt ^= 0x8000;
- comedi_buf_put(async, dpnt);
+ cfc_write_to_buffer( s, dpnt );
if(cmd->stop_src == TRIG_COUNT)
{
if(--devpriv->count == 0)
*/
-#define LABPC_DEBUG // enable debugging messages
-//#undef LABPC_DEBUG
+#undef LABPC_DEBUG
+//#define LABPC_DEBUG // enable debugging messages
#include <linux/kernel.h>
#include <linux/module.h>
#include "8253.h"
#include "8255.h"
#include "mite.h"
+#include "comedi_fc.h"
#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
s->insn_read = labpc_eeprom_read_insn;
s->insn_write = labpc_eeprom_write_insn;
+ for(i = 0; i < EEPROM_SIZE; i++)
+ {
+ devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
+ }
#ifdef LABPC_DEBUG
printk(" eeprom:");
for(i = 0; i < EEPROM_SIZE; i++)
{
- devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
printk(" %i:0x%x ", i, devpriv->eeprom_data[i]);
}
printk("\n");
lsb = thisboard->read_byte(dev->iobase + ADC_FIFO_REG);
msb = thisboard->read_byte(dev->iobase + ADC_FIFO_REG);
data = (msb << 8) | lsb;
- comedi_buf_put(async, data);
+ cfc_write_to_buffer( dev->read_subdev, data );
// quit if we have all the data we want
if(async->cmd.stop_src == TRIG_COUNT)
{
}
/* write data to comedi buffer */
- for(i=0;i<num_points;i++){
- /* XXX check for errors */
- comedi_buf_put(async, devpriv->dma_buffer[i]);
+ for( i = 0; i < num_points; i++)
+ {
+ cfc_write_to_buffer( s, devpriv->dma_buffer[i] );
}
if(async->cmd.stop_src == TRIG_COUNT) devpriv->count -= num_points;
async->buf_free_count = 0;
async->buf_read_ptr = 0;
async->buf_write_ptr = 0;
+ async->cur_chan = 0;
+ async->scan_progress = 0;
}
int comedi_command(comedi_t *d,comedi_cmd *cmd)
async->data = cmd->data;
async->data_len = cmd->data_len;
- async->cur_chan = 0;
return s->do_cmd(dev,s);
}
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;
void *data;
unsigned int data_len;
void comedi_buf_read_free(comedi_async *async, unsigned int nbytes);
unsigned int comedi_buf_read_n_available(comedi_async *async);
void comedi_buf_copy_from(comedi_async *async, void *dest, int nbytes);
+void comedi_buf_memcpy_to( comedi_async *async, unsigned int offset, const void *source,
+ unsigned int num_bytes );
+void comedi_buf_memcpy_from( comedi_async *async, unsigned int offset, void *destination,
+ unsigned int num_bytes );
//#ifdef CONFIG_COMEDI_RT