From: Frank Mori Hess Date: Fri, 15 Nov 2002 17:33:34 +0000 (+0000) Subject: Working dma analog input and output with NI 611x cards, tested 6024 to make X-Git-Tag: r0_7_66~46 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=b1dbd4f76b4ec6a5ec249e923102b7bba74e5c0e;p=comedi.git Working dma analog input and output with NI 611x cards, tested 6024 to make sure we didn't break it's analog input. DMA analog output with other boards still needs to be tested by someone. Patch is from me, Rolf Mueller, John Hallen, Herbert Peremans, Herman Bruyninckx. --- diff --git a/comedi/Config.in b/comedi/Config.in index 9bf02367..c0ea3079 100644 --- a/comedi/Config.in +++ b/comedi/Config.in @@ -80,7 +80,7 @@ dep_tristate 'DAS-6402 and compatibles' CONFIG_COMEDI_DAS6402 $CONFIG_COMEDI 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 diff --git a/comedi/comedi_fops.c b/comedi/comedi_fops.c index 410a314b..c092ae30 100644 --- a/comedi/comedi_fops.c +++ b/comedi/comedi_fops.c @@ -1358,6 +1358,9 @@ static ssize_t comedi_write_v22(struct file *file,const char *buf,size_t nbytes, 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; @@ -1437,6 +1440,10 @@ static ssize_t comedi_read_v22(struct file * file,char *buf,size_t nbytes,loff_t 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){ diff --git a/comedi/drivers.c b/comedi/drivers.c index bb6cb000..c36d6a17 100644 --- a/comedi/drivers.c +++ b/comedi/drivers.c @@ -441,9 +441,7 @@ void comedi_buf_read_free(comedi_async *async, unsigned int nbytes) { 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, diff --git a/comedi/drivers/comedi_fc.h b/comedi/drivers/comedi_fc.h index e94090aa..3cf3d7b6 100644 --- a/comedi/drivers/comedi_fc.h +++ b/comedi/drivers/comedi_fc.h @@ -29,7 +29,7 @@ #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 ) @@ -42,7 +42,8 @@ static inline unsigned int cfc_write_long_to_buffer( comedi_subdevice *subd, lsa 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 ); + diff --git a/comedi/drivers/mite.c b/comedi/drivers/mite.c index 2b000b55..229eb75e 100644 --- a/comedi/drivers/mite.c +++ b/comedi/drivers/mite.c @@ -43,7 +43,7 @@ 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: */ @@ -65,10 +65,10 @@ #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; @@ -102,6 +102,7 @@ int mite_setup(struct mite_struct *mite) { unsigned long offset, start, length; u32 addr; + int i; if(pci_enable_device(mite->pcidev)){ printk("error enabling mite\n"); @@ -111,7 +112,7 @@ int mite_setup(struct mite_struct *mite) 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; @@ -133,13 +134,12 @@ int mite_setup(struct mite_struct *mite) /* 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; @@ -180,7 +180,7 @@ void mite_unsetup(struct mite_struct *mite) 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; @@ -215,26 +215,26 @@ unsigned long mite_ll_from_kvmem(struct mite_struct *mite,comedi_async *async,in { 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; @@ -247,26 +247,26 @@ unsigned long mite_ll_from_kvmem(struct mite_struct *mite,comedi_async *async,in 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_farComedi Error: MITE_RING_SIZE is too small to hold the needed buffer\n"); @@ -283,15 +283,16 @@ unsigned long mite_ll_from_kvmem(struct mite_struct *mite,comedi_async *async,in #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); } @@ -303,47 +304,47 @@ void mite_setregs(struct mite_struct *mite,unsigned long ll_start,int chan,int d //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 @@ -351,15 +352,17 @@ void mite_setregs(struct mite_struct *mite,unsigned long ll_start,int chan,int d /**************************************/ -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){ @@ -368,38 +371,38 @@ int mite_load_buffer(struct mite_struct *mite, comedi_async *async) 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;iring[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; @@ -409,7 +412,7 @@ int mite_buf_alloc(struct mite_struct *mite, comedi_async *async, #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; @@ -420,7 +423,7 @@ int mite_buf_alloc(struct mite_struct *mite, comedi_async *async, addr += PAGE_SIZE; size -= PAGE_SIZE; } - } + } vfree(async->prealloc_buf); #endif async->prealloc_buf = NULL; @@ -432,7 +435,7 @@ int mite_buf_alloc(struct mite_struct *mite, comedi_async *async, 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; @@ -443,7 +446,7 @@ int mite_buf_alloc(struct mite_struct *mite, comedi_async *async, addr += PAGE_SIZE; size -= PAGE_SIZE; } - } + } #endif if(async->prealloc_buf == NULL){ async->prealloc_bufsz = 0; @@ -452,22 +455,23 @@ int mite_buf_alloc(struct mite_struct *mite, comedi_async *async, } 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; /* @@ -477,131 +481,229 @@ void mite_prep_dma(struct mite_struct *mite) * 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<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; }; @@ -89,23 +93,26 @@ int mite_setup(struct mite_struct *mite); 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)) diff --git a/comedi/drivers/ni_mio_common.c b/comedi/drivers/ni_mio_common.c index 8c8dc483..4da44ebe 100644 --- a/comedi/drivers/ni_mio_common.c +++ b/comedi/drivers/ni_mio_common.c @@ -53,12 +53,13 @@ */ //#define DEBUG_INTERRUPT -#define DEBUG_STATUS_A +//#define DEBUG_STATUS_A //#define DEBUG_STATUS_B #include #include "8255.h" +#include "mite.h" #ifndef MDPRINTK #define MDPRINTK(format,args...) @@ -85,7 +86,6 @@ static short ni_gainlkup[][16]={ /* 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 } }; @@ -148,7 +148,6 @@ static comedi_lrange range_ni_E_ai_611x={ 8, { 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 ), @@ -202,6 +201,7 @@ static void ni_mio_print_status_b(int status); 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, @@ -212,7 +212,6 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan, 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); @@ -247,13 +246,15 @@ static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s, 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 @@ -304,6 +305,7 @@ static void ni_E_interrupt(int irq,void *d,struct pt_regs * regs) unsigned short b_status; int wsave; unsigned int m0_status; + unsigned int m1_status; #ifdef PCIDMA struct mite_struct *mite = devpriv->mite; #endif @@ -315,30 +317,21 @@ static void ni_E_interrupt(int irq,void *d,struct pt_regs * regs) 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); } @@ -349,12 +342,12 @@ static void mite_handle_a_linkc(struct mite_struct *mite, comedi_device *dev) 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); @@ -364,23 +357,52 @@ static void mite_handle_a_linkc(struct mite_struct *mite, comedi_device *dev) 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(retasync, 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; } @@ -437,6 +459,24 @@ static void mite_handle_interrupt(comedi_device *dev,unsigned int m_status) } #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, @@ -448,6 +488,13 @@ 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){ @@ -456,15 +503,15 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status, 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 @@ -485,25 +532,26 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status, 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; @@ -514,10 +562,12 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status, #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| @@ -565,11 +615,36 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status, #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){ @@ -583,9 +658,11 @@ static void handle_b_interrupt(comedi_device *dev,unsigned short b_status) 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, @@ -593,6 +670,7 @@ static void handle_b_interrupt(comedi_device *dev,unsigned short b_status) s->async->events |= COMEDI_CB_OVERFLOW; } } +#endif b_status=win_in(AO_Status_1_Register); if(b_status&Interrupt_B_St){ @@ -653,20 +731,141 @@ static void ni_mio_print_status_b(int status) #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;ichanlist[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<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;ievents |= COMEDI_CB_OVERFLOW; @@ -693,6 +892,31 @@ static void ni_handle_fifo_half_full(comedi_device *dev) } #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 */ @@ -701,14 +925,11 @@ static void ni_handle_fifo_dregs(comedi_device *dev) 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<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;iai_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){ @@ -742,23 +950,48 @@ static void ni_handle_fifo_dregs(comedi_device *dev) } } -#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) { @@ -781,19 +1014,39 @@ 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 /* @@ -805,7 +1058,7 @@ static void ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd) 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| @@ -821,6 +1074,8 @@ static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s) 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); @@ -976,7 +1231,7 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan, 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; @@ -1010,38 +1265,23 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan, 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); @@ -1050,6 +1290,7 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan, win_out(1,ADC_FIFO_Clear); return; } + udelay(1); } } rt_printk("ni_mio_common: timeout loading channel/gain list\n"); @@ -1084,6 +1325,7 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd) { int err=0; int tmp; + int sources; /* step 1: make sure trigger sources are trivially valid */ @@ -1096,7 +1338,9 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd) 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; @@ -1119,7 +1363,8 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd) 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++; @@ -1172,15 +1417,22 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd) } } if(cmd->convert_src==TRIG_TIMER){ - if(cmd->convert_argconvert_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_argconvert_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); @@ -1190,6 +1442,11 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd) 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){ @@ -1219,13 +1476,15 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd) 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_argconvert_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_argconvert_arg*cmd->scan_end_arg){ + cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg; + err++; + } } } @@ -1241,6 +1500,7 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) 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(); @@ -1271,14 +1531,33 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) } } + 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); @@ -1304,95 +1583,87 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) 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; } @@ -1417,7 +1688,11 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) 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 */ @@ -1461,8 +1736,6 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) } #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 @@ -1484,7 +1757,7 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s) win_restore(wsave); MDPRINTK("exit ni_ai_cmd\n"); - + return 0; } @@ -1628,172 +1901,85 @@ static int ni_ai_config_analog_trig(comedi_device *dev,comedi_subdevice *s, 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;ichanlist[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;iao_conf[chan] = conf; + devpriv->ao_conf[chan] = conf; - ni_writew(conf,AO_Configuration); + ni_writew(conf,AO_Configuration); + } } - return invert; } @@ -1826,8 +2012,9 @@ static int ni_ao_insn_write_671x(comedi_device *dev,comedi_subdevice *s, 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)); @@ -1838,12 +2025,10 @@ static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s, 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); @@ -1853,8 +2038,23 @@ static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s, 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); @@ -1867,6 +2067,7 @@ static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s) { comedi_cmd *cmd = &s->async->cmd; int trigvar; + int bits; trigvar = ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST); @@ -1920,32 +2121,47 @@ static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s) 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; } @@ -2054,12 +2270,19 @@ static int ni_ao_reset(comedi_device *dev,comedi_subdevice *s) //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; @@ -2070,7 +2293,8 @@ static int ni_ao_reset(comedi_device *dev,comedi_subdevice *s) 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; @@ -2131,19 +2355,23 @@ static void mio_common_detach(comedi_device *dev) 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; @@ -2155,6 +2383,7 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it) 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; } @@ -2165,7 +2394,7 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it) 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<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; @@ -2284,8 +2514,15 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it) } /* 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"); diff --git a/comedi/drivers/ni_pcidio.c b/comedi/drivers/ni_pcidio.c index e5ed424e..86e92996 100644 --- a/comedi/drivers/ni_pcidio.c +++ b/comedi/drivers/ni_pcidio.c @@ -256,6 +256,11 @@ AT-MIO96. #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={ @@ -391,6 +396,7 @@ static void nidio_interrupt(int irq, void *d, struct pt_regs *regs) 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; @@ -402,7 +408,7 @@ static void nidio_interrupt(int irq, void *d, struct pt_regs *regs) 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){ @@ -417,7 +423,7 @@ static void nidio_interrupt(int irq, void *d, struct pt_regs *regs) #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); @@ -427,8 +433,8 @@ static void nidio_interrupt(int irq, void *d, struct pt_regs *regs) 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 */ @@ -437,19 +443,19 @@ static void nidio_interrupt(int irq, void *d, struct pt_regs *regs) 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; @@ -497,9 +503,9 @@ static void nidio_interrupt(int irq, void *d, struct pt_regs *regs) 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){ @@ -508,9 +514,9 @@ static void nidio_interrupt(int irq, void *d, struct pt_regs *regs) 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){ @@ -872,15 +878,15 @@ static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s) 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); } @@ -909,7 +915,7 @@ static int ni_pcidio_alloc(comedi_device *dev, comedi_subdevice *s, { 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); @@ -960,7 +966,7 @@ static int nidio_attach(comedi_device *dev,comedi_devconfig *it) }else{ printk(" rev=%d",readb(dev->iobase+Chip_Version)); - + s=dev->subdevices+0; dev->read_subdev = s; @@ -991,8 +997,6 @@ static int nidio_attach(comedi_device *dev,comedi_devconfig *it) } } - devpriv->mite->chan = 1; - printk("\n"); return 0; diff --git a/comedi/drivers/ni_pcimio.c b/comedi/drivers/ni_pcimio.c index 702f9903..14587140 100644 --- a/comedi/drivers/ni_pcimio.c +++ b/comedi/drivers/ni_pcimio.c @@ -22,7 +22,8 @@ /* 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, @@ -55,7 +56,7 @@ for your device. 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. */ /* @@ -64,7 +65,7 @@ Bugs: References: - + 341079b.pdf PCI E Series Register-Level Programmer Manual 340934b.pdf DAQ-STC reference manual @@ -72,16 +73,16 @@ Bugs: 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) @@ -675,11 +676,21 @@ static inline unsigned short __win_in(comedi_device *dev, int addr) #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 @@ -692,7 +703,7 @@ typedef struct{ struct mite_struct *mite; NI_PRIVATE_COMMON - + dma_addr_t ai_dma_handle; }ni_private; #define devpriv ((ni_private *)dev->private) @@ -704,6 +715,8 @@ typedef struct{ 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 */ @@ -760,6 +773,7 @@ static int pcimio_attach(comedi_device *dev,comedi_devconfig *it) if(ret<0)return ret; dev->subdevices[0].buf_alloc = pcimio_ai_alloc; + dev->subdevices[1].buf_alloc = pcimio_ao_alloc; return ret; } @@ -792,14 +806,12 @@ static int pcimio_find_device(comedi_device *dev,int bus,int slot) 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; @@ -832,4 +844,13 @@ static int pcimio_ai_alloc(comedi_device *dev, comedi_subdevice *s, #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; +} diff --git a/comedi/drivers/ni_stc.h b/comedi/drivers/ni_stc.h index 5152de95..09c00551 100644 --- a/comedi/drivers/ni_stc.h +++ b/comedi/drivers/ni_stc.h @@ -235,7 +235,14 @@ #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 @@ -397,6 +404,14 @@ #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 @@ -428,7 +443,7 @@ #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) @@ -587,7 +602,22 @@ /* 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 @@ -604,36 +634,41 @@ /* 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)) @@ -642,6 +677,14 @@ 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 }; @@ -649,10 +692,10 @@ enum caldac_enum { caldac_none=0, mb88341, dac8800, dac8043, ad8522, 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; @@ -660,10 +703,10 @@ typedef struct ni_board_struct{ 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; diff --git a/include/linux/comedidev.h b/include/linux/comedidev.h index 8f798d61..1dd34d03 100644 --- a/include/linux/comedidev.h +++ b/include/linux/comedidev.h @@ -129,6 +129,9 @@ struct comedi_subdevice_struct{ /* 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; };