Working dma analog input and output with NI 611x cards, tested 6024 to make
authorFrank Mori Hess <fmhess@speakeasy.net>
Fri, 15 Nov 2002 17:33:34 +0000 (17:33 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Fri, 15 Nov 2002 17:33:34 +0000 (17:33 +0000)
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.

comedi/Config.in
comedi/comedi_fops.c
comedi/drivers.c
comedi/drivers/comedi_fc.h
comedi/drivers/mite.c
comedi/drivers/mite.h
comedi/drivers/ni_mio_common.c
comedi/drivers/ni_pcidio.c
comedi/drivers/ni_pcimio.c
comedi/drivers/ni_stc.h
include/linux/comedidev.h

index 9bf02367188d6a7b3a162604325fb6072d057de1..c0ea307937f5e8f4b2b6691933d353da4a0317ea 100644 (file)
@@ -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
index 410a314b391dc162cf6dec47ff6162f3aa756a9d..c092ae30c7977419d312980ba6a63df0f7da47af 100644 (file)
@@ -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){
index bb6cb000509b839023cad84c6bf9dfe9fc69f5ea..c36d6a17be8b8f306b6676196aa02765834477d7 100644 (file)
@@ -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,
index e94090aa6e6661f88b32a719d18ea07fd8bedc50..3cf3d7b683f1c9e60978f6996361002138859d61 100644 (file)
@@ -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 );
+
index 2b000b55b47be357f2ae851db5c4a7c2911d1867..229eb75e9ba748323a2e33498c19c407df1ac177 100644 (file)
@@ -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:
 
 */
 #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_far<len) {
                printk("<1>Comedi 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;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;
@@ -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<<i)){
-                       printk(" %s",chsr_strings[i]);
+                       printk(" %s", bit_str[i]);
                }
        }
        printk("\n");
@@ -638,8 +740,10 @@ EXPORT_SYMBOL(mite_list_devices);
 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
 
index 524004fe0c7e1ce8fab2448ec99d98960e4fb92c..80d99dd12e8d96fbbb23498cc2ab33dd79b5db40 100644 (file)
@@ -39,6 +39,8 @@
 #define MDPRINTK(format,args...)
 #endif
 
+#define NUM_MITE_DMA_CHANNELS 4
+
 struct mite_dma_chain{
        u32 count;
        u32 addr;
@@ -46,6 +48,16 @@ struct mite_dma_chain{
        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;
@@ -55,29 +67,21 @@ struct mite_struct{
        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;
 };
@@ -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))
index 8c8dc483dbfe97e410e7c0e04a66f97108cc3828..4da44ebe35691f9f9696af4a64b95e2d884c162f 100644 (file)
 */
 
 //#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...)
@@ -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(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;
 }
@@ -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;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;
@@ -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<<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 */
@@ -717,24 +938,11 @@ static void ni_handle_fifo_dregs(comedi_device *dev)
                        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){
@@ -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_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);
 
@@ -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_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++;
+                       }
                }
        }
 
@@ -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;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;
 }
 
@@ -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<<boardtype.aobits)-1;
                if(boardtype.ao_unipolar){
@@ -2178,19 +2407,20 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
                        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;
@@ -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");
 
index e5ed424e5687e3738702ac8a683ec227645c7f84..86e9299664fd0845b525625dbce100810103a6e7 100644 (file)
@@ -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;
index 702f990394665cfc74c7afd42fa866bac49c4ec8..14587140807a4efcf6fc9aeb05bf179fc02fe9b2 100644 (file)
@@ -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;
+}
index 5152de95a1c3aff333c637aa0419dd559b5c6c74..09c00551dfaf7ae2c03e5a6c16f384d38178c069 100644 (file)
 #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 };
@@ -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;
index 8f798d61ea7ec2d9f8a57e8ad8833ea88c6564d4..1dd34d0329cd338d657054e2b0e4915cbe091894 100644 (file)
@@ -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;
 };