dep_tristate 'DAS-800 and compatibles' CONFIG_COMEDI_DAS800 $CONFIG_COMEDI
dep_tristate 'DAS-1800 and compatibles' CONFIG_COMEDI_DAS1800 $CONFIG_COMEDI
dep_tristate 'Computer Boards PCI-DAS series' CONFIG_COMEDI_CB_PCIDAS $CONFIG_COMEDI
-dep_tristate 'Computer Boards PCI-DAS64xx series' CONFIG_COMEDI_CB_PCIDAS64 $CONFIG_COMEDI
+dep_tristate 'Computer Boards PCI-DAS64xx and PCI-DAS60xx series' CONFIG_COMEDI_CB_PCIDAS64 $CONFIG_COMEDI
dep_tristate 'Computer Boards PCI-DDA series' CONFIG_COMEDI_CB_PCIDDA $CONFIG_COMEDI
dep_tristate 'Computer Boards PCIM-DDA06-16 driver' CONFIG_COMEDI_CB_PCIMDDA $CONFIG_COMEDI
dep_tristate 'Computer Boards PC-CARD-DAS16/16 driver' CONFIG_COMEDI_CB_DAS16_CS $CONFIG_COMEDI
n -= m;
retval = -EFAULT;
}
+ if( s->munge ){
+ s->munge(dev, s,async->prealloc_buf + async->buf_write_ptr, 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){
{
async->buf_read_count += nbytes;
async->buf_read_ptr += nbytes;
- if(async->buf_read_ptr >= async->prealloc_bufsz){
- async->buf_read_ptr -= async->prealloc_bufsz;
- }
+ async->buf_read_ptr %= async->prealloc_bufsz;
}
void comedi_buf_memcpy_to( comedi_async *async, unsigned int offset, const void *data,
#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,
+extern unsigned int cfc_write_array_to_buffer( comedi_subdevice *subd, void *data,
unsigned int num_bytes );
static inline unsigned int cfc_write_to_buffer( comedi_subdevice *subd, sampl_t data )
return cfc_write_array_to_buffer( subd, &data, sizeof( data ) );
};
-unsigned int cfc_read_array_from_buffer( comedi_subdevice *subd, void *data,
+extern unsigned int cfc_read_array_from_buffer( comedi_subdevice *subd, void *data,
unsigned int num_bytes );
-unsigned int cfc_handle_events( comedi_device *dev, comedi_subdevice *subd );
+extern unsigned int cfc_handle_events( comedi_device *dev, comedi_subdevice *subd );
+
321808a.pdf about at-mio-16e-10 rev P
321837a.pdf discontinuation of at-mio-16de-10 rev d
321838a.pdf about at-mio-16de-10 rev N
-
+
ISSUES:
*/
#include "mite.h"
#include "../kvmem.h"
-
#define PCI_MITE_SIZE 4096
#define PCI_DAQ_SIZE 4096
+MODULE_LICENSE("GPL");
struct mite_struct *mite_devices = NULL;
{
unsigned long offset, start, length;
u32 addr;
+ int i;
if(pci_enable_device(mite->pcidev)){
printk("error enabling mite\n");
if( pci_request_regions( mite->pcidev, "mite" ) ) {
printk("failed to request mite io regions\n");
return -EIO;
- };
+ };
addr = pci_resource_start(mite->pcidev, 0);
mite->mite_phys_addr = addr;
/* It must be here for the driver to work though */
writel(mite->daq_phys_addr | 0x80 , mite->mite_io_addr + 0xc0 );
- writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(0));
- writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(1));
-
- /* disable interrupts */
- writel(0,mite->mite_io_addr+MITE_CHCR+CHAN_OFFSET(0));
- writel(0,mite->mite_io_addr+MITE_CHCR+CHAN_OFFSET(1));
+ for( i = 0; i < NUM_MITE_DMA_CHANNELS; i++ ) {
+ writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(i));
+ /* disable interrupts */
+ writel(0,mite->mite_io_addr + MITE_CHCR + CHAN_OFFSET(i));
+ }
mite->used = 1;
return 0;
void mite_list_devices(void)
{
struct mite_struct *mite,*next;
-
+
printk("Available NI device IDs:");
if(mite_devices)for(mite=mite_devices;mite;mite=next){
next=mite->next;
{
int i,size_so_far, continuous_aq, len;
unsigned long nup;
- unsigned long prealloc_buf,prealloc_bufsz;
-
+ unsigned long prealloc_buf,prealloc_bufsz;
+
MDPRINTK("mite_ll_from_kvmem\n");
prealloc_buf=(unsigned long)async->prealloc_buf;
prealloc_bufsz=async->prealloc_bufsz;
-
+
continuous_aq = (async->cmd.stop_src == TRIG_NONE? 1:0);
if(continuous_aq) {
len = prealloc_bufsz;
}else{
len = (reqlen>prealloc_bufsz?prealloc_bufsz:reqlen);
}
-
+
//find the kernel's memory pages.
nup = (unsigned long)async->data;
i=0;
size_so_far=0;
MDPRINTK("buf=0x%08lx bufsz=0x%08lx\n",
(unsigned long)prealloc_buf,prealloc_bufsz);
-
+
while(((void*)nup < (async->data+len))&&(i<(MITE_RING_SIZE-1))) {
int count;
count = 1+TOP_OF_PAGE(nup)-nup;
nup += count;
i++;
}
-
+
/*End the mite->ring by setting the last element's count to 0.
- To make a looping ring for continuous acquisition,
+ To make a looping ring for continuous acquisition,
mite->ring[i-1].next = cpu_to_le32(virt_to_bus(mite->ring));
*/
//mite->ring[i].count=0;
-
+
if (continuous_aq&&(i>0)) {
mite->ring[i-1].next = cpu_to_le32(virt_to_bus(mite->ring+0));
mite->DMA_CheckNearEnd = 0;
}else if (prealloc_bufsz < reqlen) {
mite->ring[i-1].next = cpu_to_le32(virt_to_bus(mite->ring+0));
mite->DMA_CheckNearEnd = 1;
- }
+ }
else {
mite->ring[i].count=0;
mite->DMA_CheckNearEnd = 0;
}
-
+
MDPRINTK("i was %d, size_so_far was %d\n",i,size_so_far);
if(size_so_far<len) {
printk("<1>Comedi Error: MITE_RING_SIZE is too small to hold the needed buffer\n");
#endif
-void mite_dma_arm(struct mite_struct *mite)
+void mite_dma_arm( struct mite_struct *mite, unsigned int channel )
{
int chor;
+ MDPRINTK("mite_dma_arm ch%i\n", channel);
/* arm */
chor = CHOR_START;
- writel(chor,mite->mite_io_addr+CHAN_OFFSET(mite->chan)+MITE_CHOR);
+ writel(chor, mite->mite_io_addr + CHAN_OFFSET(channel) + MITE_CHOR);
- mite_dma_tcr(mite);
+ mite_dma_tcr(mite, channel);
}
//chan is the DMA channel to use on the MITE (0,1,2,3)
//dir is the direction of the transfer COMEDI_INPUT or COMEDI_OUTPUT
int chor,chcr,mcr,dcr,lkcr;
-
+
MDPRINTK("mite_setregs\n");
-
+
chor = CHOR_DMARESET | CHOR_FRESET; //reset DMA and FIFO
writel(chor,mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(chan));
-
+
//short link chaining mode
chcr = CHCR_SET_DMA_IE| CHCR_LINKSHORT | CHCR_SET_DONE_IE;
/*Link Complete Interrupt: interrupt every time a link in MITE_RING
is completed. This can generate a lot of extra interrupts, but right now we
- update the values of buf_int_ptr and buf_int_count at each interrupt. A
+ update the values of buf_int_ptr and buf_int_count at each interrupt. A
better method is to poll the MITE before each user "read()" to calculate the
number of bytes available. mite_bytes_transferred() is provided to get the
number of bytes transferred to system memory so far.
*/
- chcr |= CHCR_SET_LC_IE;
-
+ chcr |= CHCR_SET_LC_IE;
+
if(dir == COMEDI_INPUT){
chcr |= CHCR_DEV_TO_MEM;
}
writel(chcr,mite->mite_io_addr+MITE_CHCR+CHAN_OFFSET(chan));
-
+
//16 bits, to memory
- mcr = CR_RL64 | CR_ASEQxP1 | CR_PSIZEHALF;
+ mcr = CR_RL64 | CR_ASEQxP1 | CR_PSIZEHALF;
writel(mcr,mite->mite_io_addr+MITE_MCR+CHAN_OFFSET(chan));
//16 bits, from STC
dcr = CR_RL64 | CR_ASEQx(1) | CR_PSIZEHALF;
dcr |= CR_PORTIO | CR_AMDEVICE | CR_REQS(0x4+chan);
writel(dcr,mite->mite_io_addr+MITE_DCR+CHAN_OFFSET(chan));
-
+
//reset the DAR
writel(0,mite->mite_io_addr+MITE_DAR+CHAN_OFFSET(chan));
-
+
//the link is 32bits
lkcr = CR_RL64 | CR_ASEQUP | CR_PSIZEWORD;
writel(lkcr,mite->mite_io_addr+MITE_LKCR+CHAN_OFFSET(chan));
//starting address for link chaining
writel(ll_start,mite->mite_io_addr+MITE_LKAR+CHAN_OFFSET(chan));
-
+
MDPRINTK("exit mite_setregs\n");
}
#endif
/**************************************/
-int mite_load_buffer(struct mite_struct *mite, comedi_async *async)
+int mite_load_buffer(struct mite_struct *mite, unsigned int channel, comedi_async *async)
{
unsigned int n_links;
int i;
+ struct mite_channel *mite_chan = &mite->channels[ channel ];
- MDPRINTK("mite_load_buffer\n");
+ MDPRINTK("mite_load_buffer ch%i\n", channel);
- if(mite->ring){
- kfree(mite->ring);
+ if(mite_chan->ring){
+ kfree(mite_chan->ring);
+ mite_chan->ring = NULL;
}
if(async->prealloc_bufsz==0){
n_links = async->prealloc_bufsz >> PAGE_SHIFT;
- MDPRINTK("buf=%p bufsz=0x%08x n_links=0x%04x\n",
- async->prealloc_buf, async->prealloc_bufsz, n_links);
+ MDPRINTK("buf=%p buf(bus)=%p bufsz=0x%08x n_links=0x%04x\n",
+ async->prealloc_buf, virt_to_bus(async->prealloc_buf), async->prealloc_bufsz, n_links);
- mite->ring = kmalloc(n_links*sizeof(struct mite_dma_chain),GFP_KERNEL);
- if(!mite->ring){
+ mite_chan->ring = kmalloc(n_links * sizeof(struct mite_dma_chain), GFP_KERNEL);
+ if(!mite_chan->ring){
printk("mite: ring buffer allocation failed\n");
return -ENOMEM;
}
- mite->n_links = n_links;
- mite->current_link = 0;
+ mite_chan->n_links = n_links;
+ mite_chan->current_link = 0;
for(i=0;i<n_links;i++){
- mite->ring[i].count = cpu_to_le32(PAGE_SIZE);
+ mite_chan->ring[i].count = cpu_to_le32(PAGE_SIZE);
#ifdef USE_KMALLOC
- mite->ring[i].addr = cpu_to_le32(
+ mite_chan->ring[i].addr = cpu_to_le32(
virt_to_bus(async->prealloc_buf + i*PAGE_SIZE));
#else
- mite->ring[i].addr = cpu_to_le32(
+ mite_chan->ring[i].addr = cpu_to_le32(
kvirt_to_bus((unsigned long)async->prealloc_buf + i*PAGE_SIZE));
#endif
- mite->ring[i].next = cpu_to_le32(virt_to_bus(mite->ring+i+1));
+ mite_chan->ring[i].next = cpu_to_le32(virt_to_bus(mite_chan->ring+i+1));
}
- mite->ring[n_links-1].next = cpu_to_le32(virt_to_bus(mite->ring));
+ mite_chan->ring[n_links-1].next = cpu_to_le32(virt_to_bus(mite_chan->ring));
return 0;
}
-int mite_buf_alloc(struct mite_struct *mite, comedi_async *async,
- unsigned long new_size)
+int mite_buf_alloc(struct mite_struct *mite, unsigned int channel,
+ comedi_async *async, unsigned long new_size)
{
- MDPRINTK("mite_buf_alloc\n");
+ MDPRINTK("mite_buf_alloc ch%i\n", channel);
if(async->prealloc_buf && async->prealloc_bufsz == new_size){
return 0;
#ifdef USE_KMALLOC
kfree(async->prealloc_buf);
#else
- {
+ {
unsigned long addr = (unsigned long)async->prealloc_buf;
unsigned long size = async->prealloc_bufsz;
unsigned long page;
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
- }
+ }
vfree(async->prealloc_buf);
#endif
async->prealloc_buf = NULL;
async->prealloc_buf = kmalloc(new_size, GFP_KERNEL);
#else
async->prealloc_buf = vmalloc_32(new_size);
- {
+ {
unsigned long addr = (unsigned long)async->prealloc_buf;
unsigned long size = async->prealloc_bufsz;
unsigned long page;
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
- }
+ }
#endif
if(async->prealloc_buf == NULL){
async->prealloc_bufsz = 0;
}
async->prealloc_bufsz = new_size;
- mite_load_buffer(mite,async);
+ mite_load_buffer(mite, channel, async);
return 0;
}
-void mite_prep_dma(struct mite_struct *mite)
+void mite_prep_dma( struct mite_struct *mite, unsigned int channel,
+ unsigned int num_device_bits, unsigned int num_memory_bits )
{
unsigned int chor,chcr,mcr,dcr,lkcr;
- int chan = mite->chan;
-
- MDPRINTK("mite_prep_dma\n");
-
+ struct mite_channel *mite_chan = &mite->channels[ channel ];
+
+ MDPRINTK("mite_prep_dma ch%i\n", channel );
+
/* reset DMA and FIFO */
chor = CHOR_DMARESET | CHOR_FRESET;
- writel(chor,mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(chan));
-
+ writel(chor, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(channel));
+
/* short link chaining mode */
chcr = CHCR_SET_DMA_IE| CHCR_LINKSHORT | CHCR_SET_DONE_IE;
/*
* of buf_int_ptr and buf_int_count at each interrupt. A
* better method is to poll the MITE before each user
* "read()" to calculate the number of bytes available.
- * mite_bytes_transferred() is provided to get the number
- * of bytes transferred to system memory so far.
+ * mite_bytes_transferred(), mite_bytes_read(), and
+ * mite_bytes_in_transit() are provided to get the number
+ * of bytes transferred by the mite so far.
*/
- chcr |= CHCR_SET_LC_IE;
-
- if(mite->dir == COMEDI_INPUT){
+ chcr |= CHCR_SET_LC_IE;
+
+ if(mite_chan->dir == COMEDI_INPUT){
chcr |= CHCR_DEV_TO_MEM;
}
- writel(chcr,mite->mite_io_addr+MITE_CHCR+CHAN_OFFSET(chan));
-
- /* 16 bits, to memory */
- mcr = CR_RL64 | CR_ASEQxP1 | CR_PSIZEHALF;
- writel(mcr,mite->mite_io_addr+MITE_MCR+CHAN_OFFSET(chan));
+ writel(chcr, mite->mite_io_addr + MITE_CHCR + CHAN_OFFSET(channel));
+
+ /* to/from memory */
+ mcr = CR_RL64 | CR_ASEQxP1;
+ switch( num_memory_bits ){
+ case 8:
+ mcr |= CR_PSIZEBYTE;
+ break;
+ case 16:
+ mcr |= CR_PSIZEHALF;
+ break;
+ case 32:
+ mcr |= CR_PSIZEWORD;
+ break;
+ default:
+ rt_printk( "mite: bug! invalid mem bit width for dma transfer\n" );
+ break;
+ }
+ writel(mcr, mite->mite_io_addr + MITE_MCR + CHAN_OFFSET(channel));
+
+ /* from/to device */
+ dcr = CR_RL64 | CR_ASEQx(1);
+ dcr |= CR_PORTIO | CR_AMDEVICE | CR_REQS(0x4 + channel);
+ switch( num_device_bits ){
+ case 8:
+ dcr |= CR_PSIZEBYTE;
+ break;
+ case 16:
+ dcr |= CR_PSIZEHALF;
+ break;
+ case 32:
+ dcr |= CR_PSIZEWORD;
+ break;
+ default:
+ rt_printk( "mite: bug! invalid dev bit width for dma transfer\n" );
+ break;
+ }
+ writel(dcr, mite->mite_io_addr + MITE_DCR + CHAN_OFFSET(channel));
- /* 16 bits, from device */
- dcr = CR_RL64 | CR_ASEQx(1) | CR_PSIZEHALF;
- dcr |= CR_PORTIO | CR_AMDEVICE | CR_REQS(0x4+chan);
- writel(dcr,mite->mite_io_addr+MITE_DCR+CHAN_OFFSET(chan));
-
/* reset the DAR */
- writel(0,mite->mite_io_addr+MITE_DAR+CHAN_OFFSET(chan));
-
+ writel(0, mite->mite_io_addr + MITE_DAR + CHAN_OFFSET(channel));
+
/* the link is 32bits */
lkcr = CR_RL64 | CR_ASEQUP | CR_PSIZEWORD;
- writel(lkcr,mite->mite_io_addr+MITE_LKCR+CHAN_OFFSET(chan));
+ writel(lkcr, mite->mite_io_addr + MITE_LKCR + CHAN_OFFSET(channel));
/* starting address for link chaining */
- writel(virt_to_bus(mite->ring),
- mite->mite_io_addr+MITE_LKAR+CHAN_OFFSET(chan));
-
+ writel(virt_to_bus(mite_chan->ring),
+ mite->mite_io_addr + MITE_LKAR + CHAN_OFFSET(channel));
+
MDPRINTK("exit mite_prep_dma\n");
}
+unsigned int mite_bytes_read(struct mite_struct *mite, unsigned int chan)
+{
+ return readl(mite->mite_io_addr+MITE_DAR+CHAN_OFFSET(chan));
+}
+
+unsigned int mite_bytes_in_transit(struct mite_struct *mite, unsigned int chan)
+{
+ return readl(mite->mite_io_addr + MITE_FCR + CHAN_OFFSET(chan)) & 0x000000FF;
+}
-unsigned int mite_bytes_transferred(struct mite_struct *mite, int chan)
+unsigned int mite_bytes_transferred(struct mite_struct *mite, unsigned int chan)
{
- unsigned int dar, fcr;
+ unsigned int bytes_read;
- dar = readl(mite->mite_io_addr+MITE_DAR+CHAN_OFFSET(chan));
- fcr = readl(mite->mite_io_addr+MITE_FCR+CHAN_OFFSET(chan)) & 0x000000FF;
- return dar-fcr;
+ /* to avoid race, we want to read bytes read before reading bytes
+ * in transit */
+ bytes_read = mite_bytes_read( mite, chan );
+ return bytes_read - mite_bytes_in_transit( mite, chan );
}
-int mite_dma_tcr(struct mite_struct *mite)
+int mite_dma_tcr(struct mite_struct *mite, unsigned int channel)
{
int tcr;
int lkar;
- lkar=readl(mite->mite_io_addr+CHAN_OFFSET(mite->chan)+MITE_LKAR);
- tcr=readl(mite->mite_io_addr+CHAN_OFFSET(mite->chan)+MITE_TCR);
- MDPRINTK("lkar=0x%08x tcr=%d\n",lkar,tcr);
+ lkar=readl(mite->mite_io_addr + CHAN_OFFSET(channel) + MITE_LKAR);
+ tcr=readl(mite->mite_io_addr + CHAN_OFFSET(channel) + MITE_TCR);
+ MDPRINTK("mite_dma_tcr ch%i, lkar=0x%08x tcr=%d\n", channel, lkar, tcr);
return tcr;
}
-void mite_dma_disarm(struct mite_struct *mite)
+void mite_dma_disarm(struct mite_struct *mite, unsigned int channel)
{
int chor;
/* disarm */
chor = CHOR_ABORT;
- writel(chor,mite->mite_io_addr+CHAN_OFFSET(mite->chan)+MITE_CHOR);
+ writel(chor, mite->mite_io_addr + CHAN_OFFSET(channel) + MITE_CHOR);
}
#ifdef DEBUG_MITE
-void mite_dump_regs(struct mite_struct *mite)
+
+/* names of bits in mite registers */
+
+static char *mite_CHOR_strings[] = {
+ "start", "cont", "stop", "abort",
+ "freset", "clrlc", "clrrb", "clrdone",
+ "clr_lpause", "set_lpause", "clr_send_tc",
+ "set_send_tc", "12", "13", "14",
+ "15", "16", "17", "18",
+ "19", "20", "21", "22",
+ "23", "24", "25", "26",
+ "27", "28", "29", "30",
+ "dmareset",
+};
+
+static char *mite_CHCR_strings[] = {
+ "continue", "ringbuff", "2", "3",
+ "4", "5", "6", "7",
+ "8", "9", "10", "11",
+ "12", "13", "bursten", "fifodis",
+ "clr_cont_rb_ie", "set_cont_rb_ie", "clr_lc_ie", "set_lc_ie",
+ "clr_drdy_ie", "set_drdy_ie", "clr_mrdy_ie", "set_mrdy_ie",
+ "clr_done_ie", "set_done_ie", "clr_sar_ie", "set_sar_ie",
+ "clr_linkp_ie", "set_linkp_ie", "clr_dma_ie", "set_dma_ie",
+};
+
+static char *mite_MCR_strings[] = {
+ "amdevice", "1", "2", "3",
+ "4", "5", "portio", "portvxi",
+ "psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "11",
+ "12", "13", "blocken", "berhand",
+ "reqsintlim/reqs0", "reqs1", "reqs2", "rd32",
+ "rd512", "rl1", "rl2", "rl8",
+ "24", "25", "26", "27",
+ "28", "29", "30", "stopen",
+};
+
+static char *mite_DCR_strings[] = {
+ "amdevice", "1", "2", "3",
+ "4", "5", "portio", "portvxi",
+ "psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "aseqxp2",
+ "aseqxp8", "13", "blocken", "berhand",
+ "reqsintlim", "reqs1", "reqs2", "rd32",
+ "rd512", "rl1", "rl2", "rl8",
+ "23", "24", "25", "27",
+ "28", "wsdevc", "wsdevs", "rwdevpack",
+};
+
+static char *mite_LKCR_strings[] = {
+ "amdevice", "1", "2", "3",
+ "4", "5", "portio", "portvxi",
+ "psizebyte", "psizehalf (byte & half = word)", "asequp", "aseqdown",
+ "12", "13", "14", "berhand",
+ "16", "17", "18", "rd32",
+ "rd512", "rl1", "rl2", "rl8",
+ "24", "25", "26", "27",
+ "28", "29", "30", "chngend",
+};
+
+
+static char *mite_CHSR_strings[] = {
+ "d.err0", "d.err1", "m.err0", "m.err1",
+ "l.err0", "l.err1", "drq0", "drq1",
+ "end", "xferr", "operr0", "operr1",
+ "stops", "habort", "sabort", "error",
+ "16", "conts_rb", "18", "linkc",
+ "20", "drdy", "22", "mrdy",
+ "24", "done", "26", "sars",
+ "28", "lpauses", "30", "int",
+};
+
+void mite_dump_regs(struct mite_struct *mite, unsigned int channel)
{
unsigned long mite_io_addr = (unsigned long) mite->mite_io_addr;
unsigned long addr=0;
unsigned long temp=0;
+ printk("mite_dump_regs ch%i\n", channel);
printk("mite address is =0x%08lx\n",mite_io_addr);
-
- addr = mite_io_addr+MITE_CHOR+CHAN_OFFSET(mite->chan);
+
+ addr = mite_io_addr+MITE_CHOR+CHAN_OFFSET(channel);
printk("mite status[CHOR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr));
- //mite_decode(mite_CHOR_strings,temp);
- addr = mite_io_addr+MITE_CHCR+CHAN_OFFSET(mite->chan);
+ mite_decode(mite_CHOR_strings,temp);
+ addr = mite_io_addr+MITE_CHCR+CHAN_OFFSET(channel);
printk("mite status[CHCR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr));
- //mite_decode(mite_CHCR_strings,temp);
- addr = mite_io_addr+MITE_TCR+CHAN_OFFSET(mite->chan);
+ mite_decode(mite_CHCR_strings,temp);
+ addr = mite_io_addr+MITE_TCR+CHAN_OFFSET(channel);
printk("mite status[TCR] at 0x%08lx =0x%08x\n",addr, readl(addr));
- addr = mite_io_addr+MITE_MCR+CHAN_OFFSET(mite->chan);
+ addr = mite_io_addr+MITE_MCR+CHAN_OFFSET(channel);
printk("mite status[MCR] at 0x%08lx =0x%08lx\n",addr, temp=readl(addr));
- //mite_decode(mite_MCR_strings,temp);
-
- addr = mite_io_addr+MITE_MAR+CHAN_OFFSET(mite->chan);
+ mite_decode(mite_MCR_strings,temp);
+
+ addr = mite_io_addr+MITE_MAR+CHAN_OFFSET(channel);
printk("mite status[MAR] at 0x%08lx =0x%08x\n",addr, readl(addr));
- addr = mite_io_addr+MITE_DCR+CHAN_OFFSET(mite->chan);
+ addr = mite_io_addr+MITE_DCR+CHAN_OFFSET(channel);
printk("mite status[DCR] at 0x%08lx =0x%08lx\n",addr, temp=readl(addr));
- //mite_decode(mite_CR_strings,temp);
- addr = mite_io_addr+MITE_DAR+CHAN_OFFSET(mite->chan);
+ mite_decode(mite_CR_strings,temp);
+ addr = mite_io_addr+MITE_DAR+CHAN_OFFSET(channel);
printk("mite status[DAR] at 0x%08lx =0x%08x\n",addr, readl(addr));
- addr = mite_io_addr+MITE_LKCR+CHAN_OFFSET(mite->chan);
+ addr = mite_io_addr+MITE_LKCR+CHAN_OFFSET(channel);
printk("mite status[LKCR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr));
- //mite_decode(mite_CR_strings,temp);
- addr = mite_io_addr+MITE_LKAR+CHAN_OFFSET(mite->chan);
+ mite_decode(mite_CR_strings,temp);
+ addr = mite_io_addr+MITE_LKAR+CHAN_OFFSET(channel);
printk("mite status[LKAR]at 0x%08lx =0x%08x\n",addr, readl(addr));
- addr = mite_io_addr+MITE_CHSR+CHAN_OFFSET(mite->chan);
+ addr = mite_io_addr+MITE_CHSR+CHAN_OFFSET(channel);
printk("mite status[CHSR]at 0x%08lx =0x%08lx\n",addr, temp=readl(addr));
- mite_print_chsr(temp);
- //mite_decode(mite_CHSR_strings,temp);
- addr = mite_io_addr+MITE_FCR+CHAN_OFFSET(mite->chan);
+ mite_decode(mite_CHSR_strings,temp);
+ addr = mite_io_addr+MITE_FCR+CHAN_OFFSET(channel);
printk("mite status[FCR] at 0x%08lx =0x%08x\n\n",addr, readl(addr));
}
-
-static char *chsr_strings[] = {
- "d.err0", "d.err1", "m.err0", "m.err1",
- "l.err0", "l.err1", "drq0", "drq1",
- "end", "xferr", "operr0", "operr1",
- "stops", "habort", "sabort", "error",
- "16", "conts_rb", "18", "linkc",
- "20", "drdy", "22", "mrdy",
- "24", "done", "26", "sars",
- "28", "lpauses", "30", "int",
-};
-void mite_print_chsr(unsigned int bits)
+void mite_decode(char **bit_str, unsigned int bits)
{
int i;
- printk("chsr:");
for(i=31;i>=0;i--){
if(bits&(1<<i)){
- printk(" %s",chsr_strings[i]);
+ printk(" %s", bit_str[i]);
}
}
printk("\n");
EXPORT_SYMBOL(mite_prep_dma);
EXPORT_SYMBOL(mite_buf_alloc);
EXPORT_SYMBOL(mite_bytes_transferred);
+EXPORT_SYMBOL(mite_bytes_read);
+EXPORT_SYMBOL(mite_bytes_in_transit);
#ifdef DEBUG_MITE
-EXPORT_SYMBOL(mite_print_chsr);
+EXPORT_SYMBOL(mite_decode);
EXPORT_SYMBOL(mite_dump_regs);
#endif
#define MDPRINTK(format,args...)
#endif
+#define NUM_MITE_DMA_CHANNELS 4
+
struct mite_dma_chain{
u32 count;
u32 addr;
u32 dar;
};
+struct mite_channel{
+ int DMA_CheckNearEnd;
+
+ int dir;
+ unsigned int current_link;
+ unsigned int n_links;
+
+ struct mite_dma_chain *ring;
+};
+
struct mite_struct{
struct mite_struct *next;
int used;
void *mite_io_addr;
unsigned long daq_phys_addr;
void *daq_io_addr;
-
- int DMA_CheckNearEnd;
-
- int dir;
- int chan;
- unsigned int current_link;
- unsigned int n_links;
- struct mite_dma_chain *ring;
+ struct mite_channel channels[ NUM_MITE_DMA_CHANNELS ];
};
extern struct mite_struct *mite_devices;
-extern inline unsigned int mite_irq(struct mite_struct *mite)
+static inline unsigned int mite_irq(struct mite_struct *mite)
{
return mite->pcidev->irq;
};
-extern inline unsigned int mite_device_id(struct mite_struct *mite)
+static inline unsigned int mite_device_id(struct mite_struct *mite)
{
return mite->pcidev->device;
};
-
-extern inline unsigned long mite_iobase(struct mite_struct *mite)
+static inline unsigned long mite_iobase(struct mite_struct *mite)
{
return (unsigned long) mite->daq_io_addr;
};
void mite_unsetup(struct mite_struct *mite);
void mite_list_devices(void);
-int mite_dma_tcr(struct mite_struct *mite);
-void mite_dma_arm(struct mite_struct *mite);
-void mite_dma_disarm(struct mite_struct *mite);
-unsigned int mite_bytes_transferred(struct mite_struct *mite, int chan);
+int mite_dma_tcr(struct mite_struct *mite, unsigned int channel );
+void mite_dma_arm(struct mite_struct *mite, unsigned int channel );
+void mite_dma_disarm(struct mite_struct *mite, unsigned int channel );
+unsigned int mite_bytes_transferred(struct mite_struct *mite, unsigned int chan);
+unsigned int mite_bytes_read(struct mite_struct *mite, unsigned int chan);
+unsigned int mite_bytes_in_transit(struct mite_struct *mite, unsigned int chan);
#if 0
unsigned long mite_ll_from_kvmem(struct mite_struct *mite,comedi_async *async,int len);
void mite_setregs(struct mite_struct *mite,unsigned long ll_start,int chan, int dir);
#endif
-void mite_prep_dma(struct mite_struct *mite);
-int mite_buf_alloc(struct mite_struct *mite, comedi_async *async,
- unsigned long new_size);
+void mite_prep_dma(struct mite_struct *mite, unsigned int channel,
+ unsigned int num_device_bits, unsigned int num_memory_bits );
+int mite_buf_alloc(struct mite_struct *mite, unsigned int channel,
+ comedi_async *async, unsigned long new_size);
#ifdef DEBUG_MITE
void mite_print_chsr(unsigned int chsr);
-void mite_dump_regs(struct mite_struct *mite);
+void mite_dump_regs(struct mite_struct *mite, channel);
#endif
#define CHAN_OFFSET(x) (0x100*(x))
*/
//#define DEBUG_INTERRUPT
-#define DEBUG_STATUS_A
+//#define DEBUG_STATUS_A
//#define DEBUG_STATUS_B
#include <linux/irq.h>
#include "8255.h"
+#include "mite.h"
#ifndef MDPRINTK
#define MDPRINTK(format,args...)
/* ai_gain_4 */
{ 0, 1, 4, 7 },
/* ai_gain_611x */
- /* 0x009, gain=0.1 might be valid, but it's not useful */
{ 0x00a, 0x00b, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006 }
};
RANGE( -1, 1 ),
RANGE( -0.5, 0.5 ),
RANGE( -0.2, 0.2 ),
- //RANGE( -0.1, 0.1 ),
}};
static comedi_lrange range_ni_E_ao_ext = { 4, {
RANGE( -10, 10 ),
static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s);
#ifndef PCIDMA
static void ni_handle_fifo_half_full(comedi_device *dev);
+static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s);
#endif
static void ni_handle_fifo_dregs(comedi_device *dev);
static int ni_ai_inttrig(comedi_device *dev,comedi_subdevice *s,
static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s,
unsigned int trignum);
-static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s);
static int ni_ao_reset(comedi_device *dev,comedi_subdevice *s);
static int ni_8255_callback(int dir,int port,int data,unsigned long arg);
static void handle_a_interrupt(comedi_device *dev,unsigned short status,
unsigned int m_status);
-static void handle_b_interrupt(comedi_device *dev,unsigned short status);
+static void handle_b_interrupt(comedi_device *dev,unsigned short status,
+ unsigned int m_status);
+static void get_last_sample_611x( comedi_device *dev );
#ifdef PCIDMA
//static void mite_handle_interrupt(comedi_device *dev,unsigned int status);
-static void ni_munge(comedi_device *dev,comedi_subdevice *s,sampl_t *data, int nbytes);
+static int ni_ai_drain_dma(comedi_device *dev );
#endif
-/* ni_set_bits( ) allows different parts of the ni_mio_common driver to
+/* ni_set_bits( ) allows different parts of the ni_mio_common driver to
* share registers (such as Interrupt_A_Register) without interfering with
* each other. Use comedi_spin_lock_irqsave() and comedi_spin_unlock_irqrestore()
* if you use this to modify the interrupt enable registers...which are sometimes
unsigned short b_status;
int wsave;
unsigned int m0_status;
+ unsigned int m1_status;
#ifdef PCIDMA
struct mite_struct *mite = devpriv->mite;
#endif
you need to set up software flags for non-interrupt routines.
*/
wsave=win_save();
-
+
a_status=win_in(AI_Status_1_Register);
b_status=win_in(AO_Status_1_Register);
#ifdef PCIDMA
- m0_status=readl(mite->mite_io_addr+MITE_CHSR+CHAN_OFFSET(0));
+ m0_status=readl(mite->mite_io_addr+MITE_CHSR+CHAN_OFFSET(AI_DMA_CHAN));
+ m1_status=readl(mite->mite_io_addr+MITE_CHSR+CHAN_OFFSET(AO_DMA_CHAN));
#else
m0_status = 0;
+ m1_status = 0;
#endif
-#ifdef DEBUG_INTERRUPT
- rt_printk("ni_mio_common: interrupt: a_status=%04x b_status=%04x m0_status=%08x\n",
- a_status,b_status,m0_status);
- ni_mio_print_status_a(a_status);
- ni_mio_print_status_b(b_status);
-#endif
-
- if(a_status&Interrupt_A_St
-#ifdef PCIDMA
- || m0_status&CHSR_INT
-#endif
- ){
- handle_a_interrupt(dev,a_status,m0_status);
- }
- if(b_status&Interrupt_B_St)handle_b_interrupt(dev,b_status);
+ if(a_status&Interrupt_A_St || m0_status & CHSR_INT )
+ handle_a_interrupt(dev, a_status, m0_status);
+ if(b_status&Interrupt_B_St || m1_status & CHSR_INT )
+ handle_b_interrupt(dev, b_status, m1_status);
win_restore(wsave);
}
int count;
comedi_subdevice *s = dev->subdevices + 0;
comedi_async *async = s->async;
- int nbytes;
+ unsigned int nbytes;
int ret;
- writel(CHOR_CLRLC, mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(mite->chan));
+ writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(AI_DMA_CHAN));
- nbytes = mite_bytes_transferred(mite, 0);
+ nbytes = mite_bytes_transferred(mite, AI_DMA_CHAN);
if((int)(nbytes - async->buf_free_count) >= 0){
printk("ni_mio_common: BUG: DMA overwrite of free area\n");
ni_ai_reset(dev,s);
count = nbytes - async->buf_write_count;
- while(count >= PAGE_SIZE){
- if(!(async->cmd.flags & CMDF_RAWDATA)){
- ni_munge(dev,s,
- async->prealloc_buf + async->buf_write_ptr,
- PAGE_SIZE);
- }
- comedi_buf_write_free(async,PAGE_SIZE);
+ comedi_buf_write_free(async, count);
+
+ while( count ){
+ unsigned int block_size;
- ret = comedi_buf_write_alloc(s->async, PAGE_SIZE);
- if(ret<PAGE_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 -= PAGE_SIZE;
+ count -= ret;
+ }
+
+ async->events |= COMEDI_CB_BLOCK;
+}
+
+static void mite_handle_b_linkc(struct mite_struct *mite, comedi_device *dev)
+{
+ int count;
+ comedi_subdevice *s = dev->subdevices + 1;
+ comedi_async *async = s->async;
+ unsigned int nbytes;
+
+ writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(AO_DMA_CHAN));
+
+ nbytes = mite_bytes_read(mite, AO_DMA_CHAN);
+ // XXX this won't catch all buffer underruns
+ if((int)(nbytes - async->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;
+ }
+
+ count = nbytes - async->buf_read_count;
+ if( count < 0 ){
+ rt_printk("ni_mio_common: BUG: negative count\n");
+ count = 0;
}
+ comedi_buf_read_free(async, count);
async->events |= COMEDI_CB_BLOCK;
}
}
#endif
+static int ni_ao_wait_for_dma_load( comedi_device *dev )
+{
+ static const int timeout = 10000;
+ int i;
+
+ for( i = 0; i < timeout; i++ )
+ {
+ unsigned short b_status;
+
+ b_status = win_in( AO_Status_1_Register );
+ if( b_status & AO_FIFO_Half_Full_St )
+ break;
+ }
+ if( i == timeout ) return -EPIPE;
+
+ return 0;
+}
+
#endif //PCIDMA
static void handle_a_interrupt(comedi_device *dev,unsigned short status,
s->async->events = 0;
+#ifdef DEBUG_INTERRUPT
+ rt_printk("ni_mio_common: interrupt: a_status=%04x m0_status=%08x\n",
+ status, m_status);
+ ni_mio_print_status_a(status);
+#endif
+
+
#ifdef PCIDMA
/* Currently, mite.c requires us to handle LINKC and DONE */
if(m_status & CHSR_LINKC){
if(m_status & CHSR_DONE){
writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR +
- CHAN_OFFSET(0));
+ CHAN_OFFSET(AI_DMA_CHAN));
}
if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){
printk("unknown mite interrupt, ack! (m_status=%08x)\n", m_status);
//mite_print_chsr(m_status);
- mite_dma_disarm(devpriv->mite);
+ mite_dma_disarm(devpriv->mite, AI_DMA_CHAN );
writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR +
- CHAN_OFFSET(0));
+ CHAN_OFFSET(AI_DMA_CHAN));
//disable_irq(dev->irq);
}
#endif
rt_printk("ni_mio_common: ai error a_status=%04x\n",
status);
ni_mio_print_status_a(status);
-
+
ni_ai_reset(dev,dev->subdevices);
win_out(AI_Error_Interrupt_Ack, Interrupt_A_Ack_Register);
#ifdef PCIDMA
- mite_dma_disarm(devpriv->mite);
- mite_handle_a_linkc(devpriv->mite, dev);
+ ni_ai_drain_dma( dev );
+ mite_dma_disarm(devpriv->mite, AI_DMA_CHAN);
#endif
-
+
ni_handle_fifo_dregs(dev);
-
+ get_last_sample_611x(dev);
+
/* turn off all AI interrupts */
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);
-
+
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
return;
#endif
if(!devpriv->ai_continuous){
#ifdef PCIDMA
- mite_dma_disarm(devpriv->mite);
- mite_handle_a_linkc(devpriv->mite, dev);
+ ni_ai_drain_dma( dev );
+ mite_dma_disarm(devpriv->mite, AI_DMA_CHAN);
#endif
ni_handle_fifo_dregs(dev);
+ get_last_sample_611x(dev);
+
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|
#endif
}
-static void handle_b_interrupt(comedi_device *dev,unsigned short b_status)
+static void handle_b_interrupt(comedi_device *dev,unsigned short b_status, unsigned int m_status)
{
- int ret;
comedi_subdevice *s=dev->subdevices+1;
//unsigned short ack=0;
+#ifdef DEBUG_INTERRUPT
+ rt_printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n",
+ b_status,m_status);
+ ni_mio_print_status_b(b_status);
+#endif
+
+
+#ifdef PCIDMA
+ /* Currently, mite.c requires us to handle LINKC and DONE */
+ if(m_status & CHSR_LINKC){
+ mite_handle_b_linkc(devpriv->mite, dev);
+ }
+
+ if(m_status & CHSR_DONE){
+ writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR +
+ CHAN_OFFSET(AO_DMA_CHAN));
+ }
+
+ if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){
+ printk("unknown mite interrupt, ack! (m_status=%08x)\n", m_status);
+ //mite_print_chsr(m_status);
+ mite_dma_disarm(devpriv->mite, AO_DMA_CHAN );
+ writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR +
+ CHAN_OFFSET(AO_DMA_CHAN));
+ }
+#endif
if(b_status==0xffff)return;
if(b_status&AO_Overrun_St){
s->async->events |= COMEDI_CB_EOA;
}
+#ifndef PCIDMA
if(b_status&AO_FIFO_Request_St){
+ int ret;
+
ret = ni_ao_fifo_half_empty(dev,s);
-
if(!ret){
rt_printk("ni_mio_common: AO buffer underrun\n");
ni_set_bits(dev, Interrupt_B_Enable_Register,
s->async->events |= COMEDI_CB_OVERFLOW;
}
}
+#endif
b_status=win_in(AO_Status_1_Register);
if(b_status&Interrupt_B_St){
#endif
#ifndef PCIDMA
+
+static void ni_ao_fifo_load(comedi_device *dev,comedi_subdevice *s, int n)
+{
+ comedi_async *async = s->async;
+ comedi_cmd *cmd = &async->cmd;
+ int chan;
+ int i;
+ sampl_t d;
+ u32 packed_data;
+ int range;
+ int offset;
+ int err = 1;
+
+ offset = 1 << (boardtype.aobits - 1);
+ chan = async->cur_chan;
+ for(i=0;i<n;i++){
+ err &= comedi_buf_get(async, &d);
+ if(err == 0) break;
+
+ range = CR_RANGE(cmd->chanlist[chan]);
+ if(!boardtype.ao_unipolar || !(range & 1)){
+ d -= offset;
+ }
+
+ if( boardtype.reg_611x ){
+ packed_data = d & 0xffff;
+ err &= comedi_buf_get(async, &d);
+ if(err == 0) break;
+ d -= offset;
+ chan++;
+ i++;
+ packed_data |= ( d << 16 ) & 0xffff0000;
+ ni_writel( packed_data, DAC_FIFO_Data_611x );
+ }else{
+ ni_writew(d, DAC_FIFO_Data);
+ }
+ chan++;
+ chan %= cmd->chanlist_len;
+ }
+ async->cur_chan = chan;
+ if(err==0){
+ async->events |= COMEDI_CB_OVERFLOW;
+ }
+}
+
+/*
+ * There's a small problem if the FIFO gets really low and we
+ * don't have the data to fill it. Basically, if after we fill
+ * the FIFO with all the data available, the FIFO is _still_
+ * less than half full, we never clear the interrupt. If the
+ * IRQ is in edge mode, we never get another interrupt, because
+ * this one wasn't cleared. If in level mode, we get flooded
+ * with interrupts that we can't fulfill, because nothing ever
+ * gets put into the buffer.
+ *
+ * This kind of situation is recoverable, but it is easier to
+ * just pretend we had a FIFO underrun, since there is a good
+ * chance it will happen anyway. This is _not_ the case for
+ * RT code, as RT code might purposely be running close to the
+ * metal. Needs to be fixed eventually.
+ */
+static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s)
+{
+ int n;
+
+ n = comedi_buf_read_n_available(s->async);
+ if(n==0){
+ s->async->events |= COMEDI_CB_OVERFLOW;
+ return 0;
+ }
+
+ n /= sizeof(sampl_t);
+ if(n>boardtype.ao_fifo_depth/2)
+ n=boardtype.ao_fifo_depth/2;
+
+ ni_ao_fifo_load(dev,s,n);
+
+ s->async->events |= COMEDI_CB_BLOCK;
+
+ return 1;
+}
+
+static int ni_ao_prep_fifo(comedi_device *dev,comedi_subdevice *s)
+{
+ int n;
+
+ /* reset fifo */
+ win_out(0,DAC_FIFO_Clear);
+
+ /* load some data */
+ n = comedi_buf_read_n_available(s->async);
+ if(n==0)return 0;
+
+ n /= sizeof(sampl_t);
+ if(n>boardtype.ao_fifo_depth)
+ n=boardtype.ao_fifo_depth;
+
+ ni_ao_fifo_load(dev,s,n);
+
+ return n;
+}
+
static void ni_ai_fifo_read(comedi_device *dev,comedi_subdevice *s,
int n)
{
comedi_async *async = s->async;
int i;
- sampl_t d;
+ u32 dl;
+ sampl_t data;
unsigned int mask;
int err = 1;
mask=(1<<boardtype.adbits)-1;
- for(i=0;i<n;i++){
- d=ni_readw(ADC_FIFO_Data_Register);
- d+=devpriv->ai_xorlist[ async->cur_chan ];
- err &= comedi_buf_put(async, d);
+ if(boardtype.reg_611x){
+ for( i = 0; i < n / 2; i++ ){
+ dl=ni_readl(ADC_FIFO_Data_611x);
+
+ /* This may get the hi/lo data in the wrong order */
+ data = (dl>>16) & 0xffff;
+ err &= comedi_buf_put(s->async, data);
+ data = dl & 0xffff;
+ err &= comedi_buf_put(s->async, data);
+ }
+
+ /* Check if there's a single sample stuck in the FIFO */
+ if( n % 2){
+ dl=ni_readl(ADC_FIFO_Data_611x);
+ data = dl & 0xffff;
+ err &= comedi_buf_put(s->async, data);
+ }
+ }else{
+ for(i=0;i<n;i++){
+ data=ni_readw(ADC_FIFO_Data_Register);
+ err &= comedi_buf_put(async, data);
+ }
}
if(err==0){
async->events |= COMEDI_CB_OVERFLOW;
}
#endif
+#ifdef PCIDMA
+static int ni_ai_drain_dma(comedi_device *dev )
+{
+ struct mite_struct *mite = devpriv->mite;
+ int i;
+ static const int timeout = 10000;
+
+ for( i = 0; i < timeout; i++ )
+ {
+ if( win_in( AI_Status_1_Register ) & AI_FIFO_Empty_St &&
+ mite_bytes_in_transit( mite, AI_DMA_CHAN ) == 0 )
+ break;
+ udelay( 1 );
+ }
+ if( i == timeout )
+ {
+ rt_printk( "ni_mio_common: wait for dma drain timed out\n" );
+ return -1;
+ }
+
+ mite_handle_a_linkc( mite, dev );
+
+ return 0;
+}
+#endif
/*
Empties the AI fifo
*/
comedi_subdevice *s=dev->subdevices+0;
comedi_async *async = s->async;
sampl_t data;
- int i,n;
- unsigned int mask;
- unsigned int dl;
+ u32 dl;
int err = 1;
- mask=(1<<boardtype.adbits)-1;
if(boardtype.reg_611x){
- while(!(win_in(AI_Status_1_Register)&AI_FIFO_Empty_St)){
+ while((win_in(AI_Status_1_Register)&AI_FIFO_Empty_St) == 0){
dl=ni_readl(ADC_FIFO_Data_611x);
/* This may get the hi/lo data in the wrong order */
data = (dl&0xffff) + devpriv->ai_xorlist[async->cur_chan];
err &= comedi_buf_put(s->async, data);
}
-
- /* Check if there's a single sample stuck in the FIFO */
- if(ni_readb(Status_611x)&0x80){
- dl=ni_readl(ADC_FIFO_Data_611x);
- data = (dl&0xffff) + devpriv->ai_xorlist[async->cur_chan];
- err &= comedi_buf_put(s->async, data);
- }
}else{
- while(1){
- n = s->async->prealloc_bufsz / sizeof(sampl_t);
- for(i=0;i<n;i++){
- if(win_in(AI_Status_1_Register)&AI_FIFO_Empty_St){
- return;
- }
- data=ni_readw(ADC_FIFO_Data_Register);
- data+=devpriv->ai_xorlist[async->cur_chan];
- err &= comedi_buf_put(s->async, data);
- }
+ while((win_in(AI_Status_1_Register)&AI_FIFO_Empty_St) == 0){
+ data=ni_readw(ADC_FIFO_Data_Register);
+ data+=devpriv->ai_xorlist[async->cur_chan];
+ err &= comedi_buf_put(s->async, data);
}
}
if(err==0){
}
}
-#ifdef PCIDMA
-static void ni_munge(comedi_device *dev,comedi_subdevice *s,sampl_t *data,
- int nbytes)
+static void get_last_sample_611x( comedi_device *dev )
+{
+ comedi_subdevice *s=dev->subdevices+0;
+ comedi_async *async = s->async;
+ sampl_t data;
+ u32 dl;
+ int err = 1;
+
+ if( boardtype.reg_611x == 0 ) return;
+
+ /* Check if there's a single sample stuck in the FIFO */
+ if(ni_readb(Status_611x)&0x80){
+ dl=ni_readl(ADC_FIFO_Data_611x);
+ data = (dl&0xffff) + devpriv->ai_xorlist[async->cur_chan];
+ err &= comedi_buf_put(s->async, data);
+ }
+ if(err==0){
+ async->events |= COMEDI_CB_OVERFLOW;
+ }
+}
+
+static void ni_ai_munge(comedi_device *dev, comedi_subdevice *s,
+ void *data, unsigned int num_bytes)
{
comedi_async *async = s->async;
- unsigned int j;
+ unsigned int i;
+ unsigned int length = num_bytes / sizeof( sampl_t );
+ sampl_t *array = data;
- j=async->cur_chan;
- for(;nbytes>0;nbytes-=2){
- *data = __le16_to_cpu(*data) + devpriv->ai_xorlist[j];
- data++;
- j++;
- if(j>=async->cmd.chanlist_len)j=0;
+ for(i = 0; i < length; i++)
+ {
+#ifdef PCIDMA
+ 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;
}
- async->cur_chan=j;
}
+#ifdef PCIDMA
+
#if 0
static void ni_handle_block_dma(comedi_device *dev)
{
static void ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd)
{
struct mite_struct *mite = devpriv->mite;
+ struct mite_channel *mite_chan = &mite->channels[ AI_DMA_CHAN ];
comedi_subdevice *s = dev->subdevices + 0;
- /* mark 2 pages as being under DMA control */
+ /* mark 4 pages as being under DMA control */
comedi_buf_write_alloc(s->async, 4*PAGE_SIZE);
- mite->current_link = 0;
- mite->chan = 0;
- mite->dir = COMEDI_INPUT;
- mite_prep_dma(mite);
+ mite_chan->current_link = 0;
+ mite_chan->dir = COMEDI_INPUT;
+ if( boardtype.reg_611x )
+ mite_prep_dma(mite, AI_DMA_CHAN, 32, 16);
+ else
+ mite_prep_dma(mite, AI_DMA_CHAN, 16, 16);
/*start the MITE*/
- mite_dma_arm(mite);
+ mite_dma_arm(mite, AI_DMA_CHAN);
}
+
+static void ni_ao_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd)
+{
+ struct mite_struct *mite = devpriv->mite;
+ struct mite_channel *mite_chan = &mite->channels[ AO_DMA_CHAN ];
+
+ mite_chan->current_link = 0;
+ mite_chan->dir = COMEDI_OUTPUT;
+ if( boardtype.reg_611x )
+ mite_prep_dma(mite, AO_DMA_CHAN, 32, 32);
+ else
+ mite_prep_dma(mite, AO_DMA_CHAN, 16, 16);
+
+ /*start the MITE*/
+ mite_dma_arm(mite, AO_DMA_CHAN);
+}
+
#endif // PCIDMA
/*
static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s)
{
#ifdef PCIDMA
- mite_dma_disarm(devpriv->mite);
+ mite_dma_disarm(devpriv->mite, AI_DMA_CHAN);
#endif
ni_set_bits(dev, Interrupt_A_Enable_Register,
AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|
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(0x0000,AI_Mode_2_Register);
unsigned short offset;
unsigned int dither;
- if(n_chan==1){
+ if(n_chan == 1 && boardtype.reg_611x == 0){
if(devpriv->changain_state && devpriv->changain_spec==list[0]){
// ready to go.
return;
if(boardtype.gainlkup != ai_gain_611x){
hi=ni_modebits1[aref]|(chan&ni_modebits2[aref]);
}else{
- /* bits 12-14 channel type */
/* map everything to differential */
- hi = 0x1000;
- /* bit 11 AC/DC coupling */
- /* not handled */
- hi |= 0x0000;
- /* bits 0-2 channel */
- hi |= (chan&0x0003);
+ hi = AI_DIFFERENTIAL;
+ hi |= AI_CONFIG_CHANNEL( chan );
}
ni_writew(hi,Configuration_Memory_High);
- if(boardtype.gainlkup != ai_gain_611x){
- lo=((i==n_chan-1)?0x8000:0) | range | (dither<<9);
- }else{
- /* bits 15 last channel */
- lo = (i==n_chan-1)?0x8000:0;
- /* bits 14-10 reserved */
- /* bit 9 dither */
- lo |= (dither<<9);
- /* bit 8 unipolar/bipolar */
- /* bits 0-3 gain */
- lo |= range;
- }
+ lo = range;
+ if(i == n_chan - 1) lo |= AI_LAST_CHANNEL;
+ if( dither ) lo |= AI_DITHER;
+
ni_writew(lo,Configuration_Memory_Low);
}
/* prime the channel/gain list */
if(boardtype.reg_611x){
- /* XXX need to check if this is necessary */
win_out(1,AI_Command_1_Register);
- /* hope that it works */
return;
}else{
win_out(1,AI_Command_1_Register);
win_out(1,ADC_FIFO_Clear);
return;
}
+ udelay(1);
}
}
rt_printk("ni_mio_common: timeout loading channel/gain list\n");
{
int err=0;
int tmp;
+ int sources;
/* step 1: make sure trigger sources are trivially valid */
if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
tmp=cmd->convert_src;
- cmd->convert_src &= TRIG_TIMER|TRIG_EXT;
+ sources = TRIG_TIMER | TRIG_EXT;
+ if( boardtype.reg_611x ) sources |= TRIG_NOW;
+ cmd->convert_src &= sources;
if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
tmp=cmd->scan_end_src;
cmd->scan_begin_src!=TRIG_EXT &&
cmd->scan_begin_src!=TRIG_OTHER)err++;
if(cmd->convert_src!=TRIG_TIMER &&
- cmd->convert_src!=TRIG_EXT)err++;
+ cmd->convert_src!=TRIG_EXT &&
+ cmd->convert_src!=TRIG_NOW)err++;
if(cmd->stop_src!=TRIG_COUNT &&
cmd->stop_src!=TRIG_NONE)err++;
}
}
if(cmd->convert_src==TRIG_TIMER){
- if(cmd->convert_arg<boardtype.ai_speed){
- cmd->convert_arg=boardtype.ai_speed;
- err++;
- }
- if(cmd->convert_arg>TIMER_BASE*0xffff){
- cmd->convert_arg=TIMER_BASE*0xffff;
- err++;
+ if( boardtype.reg_611x ){
+ if(cmd->convert_arg != 0){
+ cmd->convert_arg = 0;
+ err++;
+ }
+ }else{
+ if(cmd->convert_arg<boardtype.ai_speed){
+ cmd->convert_arg=boardtype.ai_speed;
+ err++;
+ }
+ if(cmd->convert_arg>TIMER_BASE*0xffff){
+ cmd->convert_arg=TIMER_BASE*0xffff;
+ err++;
+ }
}
- }else{
+ }else if(cmd->convert_src == TRIG_EXT){
/* external trigger */
unsigned int tmp = CR_CHAN(cmd->convert_arg);
cmd->convert_arg = tmp;
err++;
}
+ }else if(cmd->convert_src == TRIG_NOW){
+ if(cmd->convert_arg != 0){
+ cmd->convert_arg = 0;
+ err++;
+ }
}
if(cmd->scan_end_arg!=cmd->chanlist_len){
if(tmp!=cmd->scan_begin_arg)err++;
}
if(cmd->convert_src==TRIG_TIMER){
- tmp=cmd->convert_arg;
- ni_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
- if(tmp!=cmd->convert_arg)err++;
- if(cmd->scan_begin_src==TRIG_TIMER &&
- cmd->scan_begin_arg<cmd->convert_arg*cmd->scan_end_arg){
- cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg;
- err++;
+ if( boardtype.reg_611x == 0){
+ tmp=cmd->convert_arg;
+ ni_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
+ if(tmp!=cmd->convert_arg)err++;
+ if(cmd->scan_begin_src==TRIG_TIMER &&
+ cmd->scan_begin_arg<cmd->convert_arg*cmd->scan_end_arg){
+ cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg;
+ err++;
+ }
}
}
int timer;
int mode1=0; /* mode1 is needed for both stop and convert */
int mode2=0;
+ int start_stop_select=0;
MDPRINTK("ni_ai_cmd\n");
wsave = win_save();
}
}
+ mode2 &= ~AI_Pre_Trigger;
+ mode2 &= ~AI_SC_Initial_Load_Source;
+ mode2 &= ~AI_SC_Reload_Mode;
+ win_out(mode2, AI_Mode_2_Register);
+
+ start_stop_select |= AI_STOP_Sync;
+ if( boardtype.reg_611x ){
+ start_stop_select |= AI_STOP_Polarity;
+ start_stop_select |= AI_STOP_Select( 31 );
+ }else{
+ start_stop_select |= AI_STOP_Select( 19 );
+ }
+ win_out(start_stop_select, AI_START_STOP_Select_Register);
+
switch(cmd->stop_src){
case TRIG_COUNT:
- /* stage number of scans */
- win_out2(cmd->stop_arg-1,AI_SC_Load_A_Registers);
+ if( boardtype.reg_611x ){
+ // have to take 3 stage adc pipeline into account
+ win_out2(cmd->stop_arg + 1, AI_SC_Load_A_Registers);
+ }
+ else{
+ /* stage number of scans */
+ win_out2(cmd->stop_arg-1,AI_SC_Load_A_Registers);
+ }
mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Trigger_Once;
win_out(mode1,AI_Mode_1_Register);
-
/* load SC (Scan Count) */
win_out(AI_SC_Load,AI_Command_1_Register);
switch(cmd->scan_begin_src){
case TRIG_TIMER:
/*
- AI_SI_Special_Trigger_Delay=0
- AI_Pre_Trigger=0
- AI_START_STOP_Select_Register:
- AI_START_Polarity=0 (?) rising edge
- AI_START_Edge=1 edge triggered
- AI_START_Sync=1 (?)
- AI_START_Select=0 SI_TC
- AI_STOP_Polarity=0 rising edge
- AI_STOP_Edge=0 level
- AI_STOP_Sync=1
- AI_STOP_Select=19 external pin (configuration mem)
+ stop stop bits for non 611x boards
+ AI_SI_Special_Trigger_Delay=0
+ AI_Pre_Trigger=0
+ AI_START_STOP_Select_Register:
+ AI_START_Polarity=0 (?) rising edge
+ AI_START_Edge=1 edge triggered
+ AI_START_Sync=1 (?)
+ AI_START_Select=0 SI_TC
+ AI_STOP_Polarity=0 rising edge
+ AI_STOP_Edge=0 level
+ AI_STOP_Sync=1
+ AI_STOP_Select=19 external pin (configuration mem)
*/
- win_out(AI_START_Edge|AI_START_Sync|
- AI_STOP_Select(19)|AI_STOP_Sync,
- AI_START_STOP_Select_Register);
+ start_stop_select |= AI_START_Edge | AI_START_Sync;
+ win_out(start_stop_select, AI_START_STOP_Select_Register);
timer=ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
win_out2(timer,AI_SI_Load_A_Registers);
+ //mode2 |= AI_SI_Reload_Mode(0);
+ mode2 |= AI_SI_Reload_Mode(1);
/* AI_SI_Initial_Load_Source=A */
- mode2 |= AI_SI_Initial_Load_Source&0;
-//mode2 |= AI_SC_Reload_Mode;
- win_out(mode2,AI_Mode_2_Register);
+ mode2 &= ~AI_SI_Initial_Load_Source;
+ //mode2 |= AI_SC_Reload_Mode;
+ win_out(mode2, AI_Mode_2_Register);
/* load SI */
win_out(AI_SI_Load,AI_Command_1_Register);
/* stage freq. counter into SI B */
win_out2(timer,AI_SI_Load_B_Registers);
-
break;
case TRIG_EXT:
- {
- unsigned int reg = 0;
- if(cmd->scan_begin_arg&CR_ALT_FILTER)
- reg |= AI_START_Edge;
+ if( cmd->scan_begin_arg & CR_EDGE )
+ start_stop_select |= AI_START_Edge;
/* AI_START_Polarity==1 is falling edge */
- if(cmd->scan_begin_arg&CR_INVERT)
- reg |= AI_START_Polarity;
- reg |= AI_START_Sync;
- reg |= AI_START_Select(1+(cmd->scan_begin_arg&0xf));
- reg |= AI_STOP_Select(19)|AI_STOP_Sync;
+ if( cmd->scan_begin_arg & CR_INVERT )
+ start_stop_select |= AI_START_Polarity;
+ start_stop_select |= AI_START_Sync;
+ start_stop_select |= AI_START_Select(1+(cmd->scan_begin_arg&0xf));
- win_out(reg,AI_START_STOP_Select_Register);
+ win_out(start_stop_select, AI_START_STOP_Select_Register);
break;
- }
}
switch(cmd->convert_src){
case TRIG_TIMER:
- timer=ni_ns_to_timer(&cmd->convert_arg,TRIG_ROUND_NEAREST);
+ if( cmd->convert_arg == 0 ) break;
+ timer=ni_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
win_out(1,AI_SI2_Load_A_Register); /* 0,0 does not work. */
win_out(timer,AI_SI2_Load_B_Register);
/* AI_SI2_Reload_Mode = alternate */
/* AI_SI2_Initial_Load_Source = A */
- win_out((AI_SI2_Initial_Load_Source&0)|
- (AI_SI2_Reload_Mode),
- AI_Mode_2_Register);
+ mode2 &= ~AI_SI2_Initial_Load_Source;
+ mode2 |= AI_SI2_Reload_Mode;
+ win_out( mode2, AI_Mode_2_Register);
/* AI_SI2_Load */
win_out(AI_SI2_Load,AI_Command_1_Register);
- //mode2 |= AI_SI_Reload_Mode(0);
- /* XXX the AI_SI stuff should go to the scan_begin_src area */
- mode2 |= AI_SI_Reload_Mode(1);
- //mode2 |= 0&AI_SI_Initial_Load_Source;
- mode2 |= AI_SI_Initial_Load_Source;
mode2 |= AI_SI2_Reload_Mode; // alternate
mode2 |= AI_SI2_Initial_Load_Source; // B
win_out(mode2,AI_Mode_2_Register);
-
break;
case TRIG_EXT:
mode1 |= AI_CONVERT_Source_Select(1+cmd->convert_arg) |
AI_CONVERT_Source_Polarity;
win_out(mode1,AI_Mode_1_Register);
- win_out(mode2 | AI_SI2_Reload_Mode,AI_Mode_2_Register);
-
mode2 |= AI_SI_Reload_Mode(0);
- mode2 |= 0&AI_SI_Initial_Load_Source;
+ mode2 &= ~AI_SI_Initial_Load_Source;
mode2 |= AI_SI2_Reload_Mode; // alternate
mode2 |= AI_SI2_Initial_Load_Source; // B
- win_out(mode2,AI_Mode_2_Register);
+ win_out(mode2, AI_Mode_2_Register);
+ break;
+ case TRIG_NOW:
break;
}
switch(devpriv->aimode){
case AIMODE_HALF_FULL:
/*generate FIFO interrupts on half-full */
+#ifdef PCIDMA
+ win_out(AI_FIFO_Mode_HF_to_E|0x0000,AI_Mode_3_Register);
+#else
win_out(AI_FIFO_Mode_HF|0x0000,AI_Mode_3_Register);
+#endif
break;
case AIMODE_SAMPLE:
/*generate FIFO interrupts on non-empty */
}
#ifdef PCIDMA
- writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR +
- CHAN_OFFSET(0));
ni_ai_setup_MITE_dma(dev,cmd);
//mite_dump_regs(devpriv->mite);
#endif
win_restore(wsave);
MDPRINTK("exit ni_ai_cmd\n");
-
+
return 0;
}
return 5;
}
-
-#if 0
/* munge data from unsigned to 2's complement for analog output bipolar modes */
static void ni_ao_munge(comedi_device *dev, comedi_subdevice *s,
- sampl_t *array, unsigned int length)
+ void *data, unsigned int num_bytes)
{
comedi_async *async = s->async;
unsigned int range;
unsigned int i;
unsigned int offset;
- unsigned int channel_index;
+ unsigned int length = num_bytes / sizeof( sampl_t );
+ sampl_t *array = data;
offset = 1 << (boardtype.aobits - 1);
for(i = 0; i < length; i++)
{
- channel_index = (async->cur_chan + i) % cmd->chanlist_len;
- range = CR_RANGE(cmd->chanlist[channel_index]);
- /* if it's a unipolar range, no munging is required */
- if(boardtype.ao_unipolar &&
- (range & 1))
- continue;
- else
+ range = CR_RANGE( async->cmd.chanlist[ async->cur_chan ] );
+ if(boardtype.ao_unipolar == 0 || (range & 1) == 0 )
array[i] -= offset;
- }
-}
+#ifdef PCIDMA
+ array[i] = __cpu_to_le16( array[i] );
#endif
-
-static void ni_ao_fifo_load(comedi_device *dev,comedi_subdevice *s, int n)
-{
- comedi_async *async = s->async;
- comedi_cmd *cmd = &async->cmd;
- int chan;
- int i;
- int port;
- sampl_t d;
- int range;
- int offset;
- int err = 1;
-
- if(boardtype.reg_611x){
- port = DAC_FIFO_Data_611x;
- }else{
- port = DAC_FIFO_Data;
- }
-
- offset = 1 << (boardtype.aobits - 1);
- chan = async->cur_chan;
- for(i=0;i<n;i++){
- err &= comedi_buf_get(async, &d);
-
- range = CR_RANGE(cmd->chanlist[chan]);
- if(!boardtype.ao_unipolar || !(range & 1)){
- d -= offset;
- }
-
- ni_writew(d,port);
-
- chan++;
- if(chan>=cmd->chanlist_len)chan=0;
- }
- async->cur_chan = chan;
- if(err==0){
- async->events |= COMEDI_CB_OVERFLOW;
+ async->cur_chan++;
+ async->cur_chan %= async->cmd.chanlist_len;
}
}
-
-/*
- * There's a small problem if the FIFO gets really low and we
- * don't have the data to fill it. Basically, if after we fill
- * the FIFO with all the data available, the FIFO is _still_
- * less than half full, we never clear the interrupt. If the
- * IRQ is in edge mode, we never get another interrupt, because
- * this one wasn't cleared. If in level mode, we get flooded
- * with interrupts that we can't fulfill, because nothing ever
- * gets put into the buffer.
- *
- * This kind of situation is recoverable, but it is easier to
- * just pretend we had a FIFO underrun, since there is a good
- * chance it will happen anyway. This is _not_ the case for
- * RT code, as RT code might purposely be running close to the
- * metal. Needs to be fixed eventually.
- */
-static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s)
-{
- int n;
-
- n = comedi_buf_read_n_available(s->async);
- if(n==0){
- s->async->events |= COMEDI_CB_OVERFLOW;
- return 0;
- }
-
- n /= sizeof(sampl_t);
- if(n>boardtype.ao_fifo_depth/2)
- n=boardtype.ao_fifo_depth/2;
-
- ni_ao_fifo_load(dev,s,n);
-
- s->async->events |= COMEDI_CB_BLOCK;
-
- return 1;
-}
-
-static int ni_ao_prep_fifo(comedi_device *dev,comedi_subdevice *s)
-{
- int n;
-
- /* reset fifo */
- win_out(0,DAC_FIFO_Clear);
-
- /* load some data */
- n = comedi_buf_read_n_available(s->async);
- if(n==0)return 0;
-
- n /= sizeof(sampl_t);
- if(n>boardtype.ao_fifo_depth)
- n=boardtype.ao_fifo_depth;
-
- ni_ao_fifo_load(dev,s,n);
-
- return n;
-}
-
static int ni_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
unsigned int chanspec[], unsigned int n_chans)
{
unsigned int range;
unsigned int chan;
unsigned int conf;
- int i;
+ int i, bits;
int invert = 0;
- for(i=0;i<n_chans;i++){
- chan = CR_CHAN(chanspec[i]);
- range = CR_RANGE(chanspec[i]);
-
- conf = AO_Channel(chan);
+ if( boardtype.reg_611x ){
+ ao_win_out( CLEAR_WG, AO_Misc_611x);
- if(boardtype.ao_unipolar){
- if((range&1) == 0){
+ bits = 0;
+ for(i = 0; i < n_chans; i++){
+ chan = CR_CHAN( chanspec[i] );
+ bits |= 1 << chan;
+ ao_win_out( chan, AO_Waveform_Generation_611x);
+ }
+ ao_win_out(~bits & 0x3, AO_Immediate_671x);
+ ao_win_out(bits, AO_Timed_611x);
+ }else{
+ for(i=0;i<n_chans;i++){
+ chan = CR_CHAN(chanspec[i]);
+ range = CR_RANGE(chanspec[i]);
+
+ conf = AO_Channel(chan);
+
+ if(boardtype.ao_unipolar){
+ if((range&1) == 0){
+ conf |= AO_Bipolar;
+ invert = (1<<(boardtype.aobits-1));
+ }else{
+ invert = 0;
+ }
+ if(range&2)
+ conf |= AO_Ext_Ref;
+ }else{
conf |= AO_Bipolar;
invert = (1<<(boardtype.aobits-1));
- }else{
- invert = 0;
}
- if(range&2)
- conf |= AO_Ext_Ref;
- }else{
- conf |= AO_Bipolar;
- invert = (1<<(boardtype.aobits-1));
- }
- /* not all boards can deglitch, but this shouldn't hurt */
- if(chanspec[i] & CR_DEGLITCH)
- conf |= AO_Deglitch;
+ /* not all boards can deglitch, but this shouldn't hurt */
+ if(chanspec[i] & CR_DEGLITCH)
+ conf |= AO_Deglitch;
- /* analog reference */
- /* AREF_OTHER connects AO ground to AI ground, i think */
- conf |= (CR_AREF(chanspec[i])==AREF_OTHER)? AO_Ground_Ref : 0;
+ /* analog reference */
+ /* AREF_OTHER connects AO ground to AI ground, i think */
+ conf |= (CR_AREF(chanspec[i])==AREF_OTHER)? AO_Ground_Ref : 0;
- devpriv->ao_conf[chan] = conf;
+ devpriv->ao_conf[chan] = conf;
- ni_writew(conf,AO_Configuration);
+ ni_writew(conf,AO_Configuration);
+ }
}
-
return invert;
}
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int invert;
- invert = ni_ao_config_chanlist(dev,s,&insn->chanspec,1);
+ ao_win_out(1 << chan, AO_Immediate_671x);
+ invert = 1 << (boardtype.aobits - 1);
devpriv->ao[chan] = data[0];
ao_win_out(data[0] ^ invert, DACx_Direct_Data_671x(chan));
unsigned int trignum)
{
int ret;
+ int bits;
if(trignum!=0)return -EINVAL;
- ret = ni_ao_prep_fifo(dev,s);
- if(ret==0)return -EPIPE;
-
win_out(devpriv->ao_mode3|AO_Not_An_UPDATE,AO_Mode_3_Register);
win_out(devpriv->ao_mode3,AO_Mode_3_Register);
win_out(devpriv->ao_cmd1|AO_UI_Arm|AO_UC_Arm|AO_BC_Arm|AO_DAC1_Update_Mode|AO_DAC0_Update_Mode,
AO_Command_1_Register);
- ni_set_bits(dev, Interrupt_B_Enable_Register,
- AO_FIFO_Interrupt_Enable|AO_Error_Interrupt_Enable, 1);
+ bits = AO_Error_Interrupt_Enable;
+#ifdef PCIDMA
+ win_out(0, DAC_FIFO_Clear);
+ // offset load doesn't seem to be necessary
+ //ao_win_out( 0x6, AO_FIFO_Offset_Load_611x );
+ ni_ao_setup_MITE_dma(dev, &s->async->cmd);
+ ret = ni_ao_wait_for_dma_load(dev);
+ if(ret < 0) return ret;
+
+ ni_set_bits(dev, Interrupt_B_Enable_Register, AO_FIFO_Interrupt_Enable, 0);
+#else
+ ret = ni_ao_prep_fifo(dev,s);
+ if(ret==0)return -EPIPE;
+
+ bits |= AO_FIFO_Interrupt_Enable;
+#endif
+ ni_set_bits(dev, Interrupt_B_Enable_Register, bits, 1);
win_out(devpriv->ao_cmd2|AO_START1_Pulse,AO_Command_2_Register);
{
comedi_cmd *cmd = &s->async->cmd;
int trigvar;
+ int bits;
trigvar = ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
win_out(AO_UI_Load,AO_Command_1_Register);
win_out2(trigvar,AO_UI_Load_A_Register);
- if(cmd->scan_end_arg>1){
- devpriv->ao_mode1|=AO_Multiple_Channels;
- win_out(AO_Number_Of_Channels(cmd->scan_end_arg-1)|
- AO_UPDATE_Output_Select(1),
- AO_Output_Control_Register);
- }else{
- devpriv->ao_mode1&=~AO_Multiple_Channels;
- win_out(AO_Number_Of_Channels(CR_CHAN(cmd->chanlist[0]))|
- AO_UPDATE_Output_Select(1),
- AO_Output_Control_Register);
+ if( boardtype.reg_611x == 0 ){
+ if(cmd->scan_end_arg>1){
+ devpriv->ao_mode1|=AO_Multiple_Channels;
+ win_out(AO_Number_Of_Channels(cmd->scan_end_arg-1)|
+ AO_UPDATE_Output_Select(1),
+ AO_Output_Control_Register);
+ }else{
+ devpriv->ao_mode1&=~AO_Multiple_Channels;
+ win_out(AO_Number_Of_Channels(CR_CHAN(cmd->chanlist[0]))|
+ AO_UPDATE_Output_Select(1),
+ AO_Output_Control_Register);
+ }
+ win_out(devpriv->ao_mode1,AO_Mode_1_Register);
}
- win_out(devpriv->ao_mode1,AO_Mode_1_Register);
win_out(AO_DAC0_Update_Mode|AO_DAC1_Update_Mode,AO_Command_1_Register);
devpriv->ao_mode3|=AO_Stop_On_Overrun_Error;
win_out(devpriv->ao_mode3,AO_Mode_3_Register);
-devpriv->ao_mode2|=AO_FIFO_Mode(1);
- devpriv->ao_mode2&=~AO_FIFO_Retransmit_Enable;
+ devpriv->ao_mode2 &= AO_FIFO_Mode_Mask;
+#ifdef PCIDMA
+ devpriv->ao_mode2 |= AO_FIFO_Mode_HF_to_F;
+#else
+ devpriv->ao_mode2 |= AO_FIFO_Mode_HF;
+#endif
+ devpriv->ao_mode2 &= ~AO_FIFO_Retransmit_Enable;
win_out(devpriv->ao_mode2,AO_Mode_2_Register);
+ bits = AO_BC_Source_Select | AO_UPDATE_Pulse_Width |
+ AO_TMRDACWR_Pulse_Width;
+ if( boardtype.ao_fifo_depth )
+ bits |= AO_FIFO_Enable;
+ win_out(bits, AO_Personal_Register);
+ // enable sending of ao dma requests
+ win_out(AO_AOFREQ_Enable, AO_Start_Select_Register);
+
win_out(AO_Configuration_End,Joint_Reset_Register);
s->async->inttrig=ni_ao_inttrig;
-
+
return 0;
}
//devpriv->ao1p=AO_Channel(1);
//ni_writew(devpriv->ao1p,AO_Configuration);
+#ifdef PCIDMA
+ mite_dma_disarm(devpriv->mite, AO_DMA_CHAN);
+ writel(CHOR_DMARESET | CHOR_FRESET, devpriv->mite->mite_io_addr + MITE_CHOR +
+ CHAN_OFFSET(AO_DMA_CHAN));
+#endif
+
win_out(AO_Configuration_Start,Joint_Reset_Register);
win_out(AO_Disarm,AO_Command_1_Register);
win_out(0,Interrupt_B_Enable_Register);
win_out(0x0010,AO_Personal_Register);
win_out(0x3f98,Interrupt_B_Ack_Register);
- win_out(0x1430,AO_Personal_Register);
+ win_out(AO_BC_Source_Select | AO_UPDATE_Pulse_Width |
+ AO_TMRDACWR_Pulse_Width, AO_Personal_Register);
win_out(0,AO_Output_Control_Register);
win_out(0,AO_Start_Select_Register);
devpriv->ao_cmd1=0;
devpriv->ao_mode3=0;
devpriv->ao_trigger_select=0;
if(boardtype.ao_671x){
- ao_win_out(0xff,AO_Immediate_671x);
+ ao_win_out(0x3, AO_Immediate_671x);
+ ao_win_out(CLEAR_WG, AO_Misc_611x);
}
return 0;
static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
{
comedi_subdevice *s;
-
+ int bits;
+
dev->n_subdevices=8;
-
+
if(alloc_subdevices(dev)<0)
return -ENOMEM;
-
+
/* analog input subdevice */
s=dev->subdevices+0;
dev->read_subdev=s;
if(boardtype.n_adchan){
s->type=COMEDI_SUBD_AI;
- s->subdev_flags=SDF_READABLE|SDF_GROUND|SDF_COMMON|SDF_DIFF|SDF_OTHER;
+ s->subdev_flags=SDF_READABLE|SDF_DIFF;
+ if( boardtype.reg_611x == 0 ) // driver doesn't seem to support ground/common for any boards?
+ s->subdev_flags |= SDF_GROUND | SDF_COMMON;
+
s->subdev_flags|=SDF_DITHER;
s->n_chan=boardtype.n_adchan;
s->len_chanlist=512;
s->do_cmd=ni_ai_cmd;
s->cancel=ni_ai_reset;
s->poll=ni_ai_poll;
+ s->munge=ni_ai_munge;
}else{
s->type=COMEDI_SUBD_UNUSED;
}
if(boardtype.n_aochan){
dev->write_subdev=s;
s->type=COMEDI_SUBD_AO;
- s->subdev_flags=SDF_WRITABLE|SDF_DEGLITCH|SDF_GROUND|SDF_OTHER;
+ s->subdev_flags=SDF_WRITABLE|SDF_DEGLITCH|SDF_GROUND;
s->n_chan=boardtype.n_aochan;
s->maxdata=(1<<boardtype.aobits)-1;
if(boardtype.ao_unipolar){
s->insn_write=ni_ao_insn_write_671x;
}else{
s->insn_write=ni_ao_insn_write;
- if(boardtype.ao_fifo_depth){
- s->do_cmd=ni_ao_cmd;
- s->do_cmdtest=ni_ao_cmdtest;
- s->len_chanlist = 2;
- }
+ }
+ if(boardtype.ao_fifo_depth){
+ s->do_cmd=ni_ao_cmd;
+ s->do_cmdtest=ni_ao_cmdtest;
+ s->len_chanlist = 2;
}
s->cancel=ni_ao_reset;
+ s->munge=ni_ao_munge;
}else{
s->type=COMEDI_SUBD_UNUSED;
}
-
+
/* digital i/o subdevice */
-
+
s=dev->subdevices+2;
s->type=COMEDI_SUBD_DIO;
s->subdev_flags=SDF_WRITABLE|SDF_READABLE;
}
/* DMA setup */
- /* tell the STC to use DMA0 for AI, DMA1 for AO */
- ni_writeb(0x21,AI_AO_Select);
+ /* tell the STC which dma channels to use for AI and AO */
+ bits = 1 << ( AI_DMA_CHAN );
+ bits |= 1 << ( AO_DMA_CHAN + 4 );
+ ni_writeb( bits, AI_AO_Select);
+ /* tell the STC which dma channels to use for
+ * General purpose counters 0 and 1 */
+ bits = 1 << ( GPC0_DMA_CHAN );
+ bits |= 1 << ( GPC1_DMA_CHAN + 4 );
+ ni_writeb( bits, G0_G1_Select);
printk("\n");
#define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC)
#endif
+enum mite_dma_channels
+{
+ DI_DMA_CHAN = 1,
+};
+
static int nidio_attach(comedi_device *dev,comedi_devconfig *it);
static int nidio_detach(comedi_device *dev);
static comedi_driver driver_pcidio={
comedi_subdevice *s = dev->subdevices;
comedi_async *async = s->async;
struct mite_struct *mite = devpriv->mite;
+ struct mite_channel *mite_chan = &mite->channels[ DI_DMA_CHAN ];
//int i, j;
long int AuxData = 0;
sampl_t data1 = 0;
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));
+ m_status = readl(mite->mite_io_addr + MITE_CHSR + CHAN_OFFSET( DI_DMA_CHAN ));
//interrupcions parasites
if(dev->attached == 0){
#ifdef MITE_DEBUG
mite_print_chsr(m_status);
#endif
- //printk("mite_bytes_transferred: %d\n",mite_bytes_transferred(mite,1));
+ //printk("mite_bytes_transferred: %d\n",mite_bytes_transferred(mite,DI_DMA_CHAN));
//mite_dump_regs(mite);
//printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf);
if(m_status & CHSR_LINKC){
unsigned int count;
- writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(1));
- count = le32_to_cpu(mite->ring[mite->current_link].count);
+ writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(DI_DMA_CHAN));
+ count = le32_to_cpu(mite_chan->ring[mite_chan->current_link].count);
/* XXX need to byteswap */
if(async->buf_write_ptr >= async->prealloc_bufsz){
async->buf_write_ptr -= async->prealloc_bufsz;
}
- mite->current_link++;
- if(mite->current_link >= mite->n_links){
- mite->current_link=0;
+ mite_chan->current_link++;
+ if(mite_chan->current_link >= mite_chan->n_links){
+ mite_chan->current_link=0;
}
}
if(m_status & CHSR_DONE){
writel(CHOR_CLRDONE, mite->mite_io_addr + MITE_CHOR +
- CHAN_OFFSET(1));
+ CHAN_OFFSET( DI_DMA_CHAN ));
}
if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_DRDY | CHSR_DRQ1)){
DPRINTK("unknown mite interrupt, disabling IRQ\n");
writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR +
- CHAN_OFFSET(1));
+ CHAN_OFFSET( DI_DMA_CHAN ));
disable_irq(dev->irq);
}
async->events |= COMEDI_CB_BLOCK;
writeb(0x00,dev->iobase+OpMode);
writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
#ifdef USE_DMA
- mite_dma_disarm(mite);
+ mite_dma_disarm(mite, DI_DMA_CHAN);
writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR +
- CHAN_OFFSET(1));
+ CHAN_OFFSET( DI_DMA_CHAN ));
#endif
break;
}else if(flags & Waited){
writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control);
async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
#ifdef USE_DMA
- mite_dma_disarm(mite);
+ mite_dma_disarm(mite, DI_DMA_CHAN);
writel(CHOR_DMARESET, mite->mite_io_addr + MITE_CHOR +
- CHAN_OFFSET(1));
+ CHAN_OFFSET( DI_DMA_CHAN ));
#endif
break;
}else if(flags & PrimaryTC){
static void setup_mite_dma(comedi_device *dev,comedi_subdevice *s)
{
struct mite_struct *mite = devpriv->mite;
+ struct mite_channel *mite_chan = &mite->channels[ DI_DMA_CHAN ];
- mite->current_link = 0;
+ mite_chan->current_link = 0;
- mite->dir = COMEDI_INPUT;
- mite->chan = 1;
+ mite_chan->dir = COMEDI_INPUT;
- mite_prep_dma(mite);
+ mite_prep_dma(mite, DI_DMA_CHAN, 16, 16);
- mite_dma_arm(mite);
+ mite_dma_arm(mite, DI_DMA_CHAN);
}
{
int ret;
- ret = mite_buf_alloc(devpriv->mite, s->async, new_size);
+ ret = mite_buf_alloc(devpriv->mite, DI_DMA_CHAN, s->async, new_size);
if(ret<0)return ret;
memset(s->async->prealloc_buf, 0xaa, s->async->prealloc_bufsz);
}else{
printk(" rev=%d",readb(dev->iobase+Chip_Version));
-
+
s=dev->subdevices+0;
dev->read_subdev = s;
}
}
- devpriv->mite->chan = 1;
-
printk("\n");
return 0;
/*
Driver: ni_pcimio.o
Description: National Instruments PCI-MIO-E series (all boards)
-Author: ds
+Author: ds, John Hallen, Frank Mori Hess, Rolf Mueller, Herbert Peremans,
+ Herman Bruyninckx
Status: works
Devices: [National Instruments] PCI-MIO-16XE-50 (ni_pcimio),
PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, PCI-MIO-16E-4, PCI-6040E,
Bugs:
- When DMA is enabled, COMEDI_EV_SCAN_END and COMEDI_EV_CONVERT do
not work correctly.
- - There are reported problems with the 61xx and 67xx boards.
+ - There are reported problems with the 67xx boards.
*/
/*
References:
-
+
341079b.pdf PCI E Series Register-Level Programmer Manual
340934b.pdf DAQ-STC reference manual
320945c.pdf PCI E Series User Manual
322138a.pdf PCI-6052E and DAQPad-6052E User Manual
-
+
ISSUES:
need to deal with external reference for DAC, and other DAC
properties in board properties
-
+
deal with at-mio-16de-10 revision D to N changes, etc.
-
+
need to add other CALDAC type
-
+
need to slow down DAC loading. I don't trust NI's claim that
two writes to the PCI bus slows IO enough. I would prefer to
use udelay(). Timing specs: (clock)
#define win_save() (ni_readw(Window_Address))
#define win_restore(a) (ni_writew((a),Window_Address))
-#define ao_win_out(a,b) do{ \
- ni_writew((b),AO_Window_Address_671x); \
- ni_writew((a),AO_Window_Data_671x); \
-}while(0)
+#define ao_win_out(data,addr) __ao_win_out(dev,data,addr)
+static inline void __ao_win_out( comedi_device *dev, uint16_t data, int addr )
+{
+ unsigned long flags;
+ comedi_spin_lock_irqsave(&dev->spinlock,flags);
+ ni_writew(addr,AO_Window_Address_671x);
+ ni_writew(data,AO_Window_Data_671x);
+ comedi_spin_unlock_irqrestore(&dev->spinlock,flags);
+}
+
+#define ao_win_out2(data,addr) do{ \
+ ao_win_out((data)>>16, (addr)); \
+ ao_win_out((data)&0xffff, (addr)+1); \
+}while(0)
#define interrupt_pin(a) 0
struct mite_struct *mite;
NI_PRIVATE_COMMON
-
+
dma_addr_t ai_dma_handle;
}ni_private;
#define devpriv ((ni_private *)dev->private)
static int pcimio_find_device(comedi_device *dev,int bus,int slot);
static int pcimio_ai_alloc(comedi_device *dev, comedi_subdevice *s,
unsigned long new_size);
+static int pcimio_ao_alloc(comedi_device *dev, comedi_subdevice *s,
+ unsigned long new_size);
/* cleans up allocated resources */
if(ret<0)return ret;
dev->subdevices[0].buf_alloc = pcimio_ai_alloc;
+ dev->subdevices[1].buf_alloc = pcimio_ao_alloc;
return ret;
}
return -EIO;
}
-/* This needs to be fixed before it can be used for AO, since it
- * uses devpriv->ai_dma_handle */
static int pcimio_ai_alloc(comedi_device *dev, comedi_subdevice *s,
unsigned long new_size)
{
int ret;
- ret = mite_buf_alloc(devpriv->mite, s->async, new_size);
+ ret = mite_buf_alloc(devpriv->mite, AI_DMA_CHAN, s->async, new_size);
if(ret<0)return ret;
return 0;
#endif
}
+static int pcimio_ao_alloc(comedi_device *dev, comedi_subdevice *s,
+ unsigned long new_size)
+{
+ int ret;
+
+ ret = mite_buf_alloc(devpriv->mite, AO_DMA_CHAN, s->async, new_size);
+ if(ret<0)return ret;
+ return 0;
+}
#define AO_Trigger_Once _bit0
#define AO_Mode_2_Register 39
-#define AO_FIFO_Mode(x) ((x)<<14)
+#define AO_FIFO_Mode_Mask ( 0x3 << 14 )
+enum AO_FIFO_Mode_Bits
+{
+ AO_FIFO_Mode_HF_to_F = (3<<14),
+ AO_FIFO_Mode_F = (2<<14),
+ AO_FIFO_Mode_HF = (1<<14),
+ AO_FIFO_Mode_E = (0<<14),
+};
#define AO_FIFO_Retransmit_Enable _bit13
#define AO_START1_Disable _bit12
#define AO_UC_Initial_Load_Source _bit11
#define AI_AIFREQ_Polarity _bit4
#define AO_Personal_Register 78
+enum AO_Personal_Bits
+{
+ AO_BC_Source_Select = 1 << 4,
+ AO_UPDATE_Pulse_Width = 1 << 5,
+ AO_AOFREQ_Polarity = 1 << 9,
+ AO_FIFO_Enable = 1 << 10,
+ AO_TMRDACWR_Pulse_Width = 1 << 12,
+};
#define Write_Strobe_0_Register 82
#define Write_Strobe_1_Register 83
#define Write_Strobe_2_Register 84
#define AI_External_Gate_Select(a) (a)
#define G_Autoincrement_Register(a) (68+(a))
-#define G_Command_Register(a) (6+(a))
+#define G_Command_Register(a) (6+(a))
#define G_HW_Save_Register(a) (8+(a)*2)
#define G_HW_Save_Register_High(a) (8+(a)*2)
#define G_HW_Save_Register_Low(a) (9+(a)*2)
/* 16 bit registers */
#define Configuration_Memory_Low 0x10
+enum Configuration_Memory_Low_Bits
+{
+ AI_DITHER = 0x200,
+ AI_LAST_CHANNEL = 0x8000,
+};
#define Configuration_Memory_High 0x12
+enum Configuration_Memory_High_Bits
+{
+ AI_AC_COUPLE = 0x800,
+ AI_DIFFERENTIAL = 0x1000,
+};
+static inline unsigned int AI_CONFIG_CHANNEL( unsigned int channel )
+{
+ return ( channel & 0x7 );
+}
+
#define ADC_FIFO_Data_Register 0x1c
#define AO_Configuration 0x16
/* 611x registers (these boards differ from the e-series) */
-#define Serial_Command_611x 0x0d /* w8 (same) */
-#define Misc_Command_611x 0x0f /* w8 (addtional bits) */
#define Magic_611x 0x19 /* w8 (new) */
#define Status_611x 0x01 /* r8 (additional bits) */
+enum Status_611x_Bits
+{
+ AI_FIFO_LOWER_NOT_EMPTY = 0x8,
+};
#define Calibration_Channel_Select_611x 0x1a /* w16 (new) */
#define ADC_FIFO_Data_611x 0x1c /* r32 (incompatible) */
-#define Configuration_Memory_Low_611x 0x10 /* w16 (same) */
-#define Configuration_Memory_High_611x 0x12 /* w16 (additional bits) */
#define AI_FIFO_Offset_Load_611x 0x05 /* r8 (new) */
+#define AO_FIFO_Offset_Load_611x 0x13 /* W32? */
#define AO_Configuration_611x 0x16 /* w16 */
#define DAC_FIFO_Data_611x 0x14 /* w32 (incompatible) */
#define AO_Window_Addr_611x 0x18 /* w16 */
#define AO_Window_Data_611x 0x1e /* w16 */
#define Cal_Gain_Select_611x 0x05 /* w8 (new) */
-#define AI_AO_Select_611x 0x09 /* w8 */
-#define G0_G1_Select_611x 0x0b /* w8 */
/* AO Windowed registers */
-/* 671x registers */
+/* 671x, 611x registers */
#define AO_Window_Address_671x 0x18 /* W 16 */
#define AO_Window_Data_671x 0x1e /* W 16 */
-/* 671x windowed registers */
+/* 671xi, 611x windowed ao registers */
#define DACx_Direct_Data_671x(x) (x) /* W 16 */
#define AO_Immediate_671x 0x11 /* W 16 */
-
-
+#define AO_Timed_611x 0x10 /* W 16 */
+#define AO_Later_Single_Point_Updates 0x14 /* W 16 */
+#define AO_Waveform_Generation_611x 0x15 /* W 16 */
+#define AO_Misc_611x 0x16 /* W 16 */
+enum AO_Misc_611x_Bits
+{
+ CLEAR_WG = 1,
+};
#define SerDacLd(x) (0x08<<(x))
but I thought I'd put it here anyway.
*/
+/* our default usage of mite channels */
+enum mite_dma_channel{
+ AI_DMA_CHAN = 0,
+ AO_DMA_CHAN = 1,
+ GPC0_DMA_CHAN = 2,
+ GPC1_DMA_CHAN = 3,
+};
+
enum{ ai_gain_16=0, ai_gain_8, ai_gain_14, ai_gain_4, ai_gain_611x };
enum caldac_enum { caldac_none=0, mb88341, dac8800, dac8043, ad8522,
ad8804, ad8842, ad8804_debug };
typedef struct ni_board_struct{
int device_id;
char *name;
-
+
int n_adchan;
int adbits;
-
+
int ai_fifo_depth;
unsigned int alwaysdither : 1;
int gainlkup;
int n_aochan;
int aobits;
-
+
int ao_fifo_depth;
int aorangelkup;
-
+
unsigned int ao_unipolar : 1;
unsigned int has_8255 : 1;
unsigned int has_analog_trig : 1;
/* buffer allocation overload function */
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 state;
};