Added some ack'ing of b interrupts, and do acks before handling
[comedi.git] / comedi / drivers / ni_mio_common.c
index 8b586ac5020dc5482c17cf2b21dd27ec78432d48..0bab766abd9250b0eb5a673556e3f17d5c6c920c 100644 (file)
@@ -4,7 +4,7 @@
 
     COMEDI - Linux Control and Measurement Device Interface
     Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
-    Copyright (C) 2002, 2003 Frank Mori Hess <fmhess@users.sourceforge.net
+    Copyright (C) 2002-2006 Frank Mori Hess <fmhess@users.sourceforge.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -52,7 +52,9 @@
        ISSUES:
 
         - the interrupt routine needs to be cleaned up
-        - many printk's need to be changed to rt_printk()
+
+       2006-02-07: S-Series PCI-6143: Support has been added but is not
+               fully tested as yet. Terry Barnaby, BEAM Ltd.
 */
 
 //#define DEBUG_INTERRUPT
@@ -68,8 +70,8 @@
 #endif
 
 /* A timeout count */
-
 #define NI_TIMEOUT 1000
+static const unsigned old_RTSI_clock_channel = 7;
 
 /* Note: this table must match the ai_gain_* definitions */
 static short ni_gainlkup[][16]={
@@ -84,7 +86,13 @@ static short ni_gainlkup[][16]={
        /* ai_gain_4 */
        { 0, 1, 4, 7 },
        /* ai_gain_611x */
-       { 0x00a, 0x00b, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006 }
+       { 0x00a, 0x00b, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006 },
+       /* ai_gain_622x */
+       { 0, 1, 4, 5},
+       /* ai_gain_628x */
+       { 1, 2, 3, 4, 5, 6, 7},
+       /* ai_gain_6143 */
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
 };
 
 static comedi_lrange range_ni_E_ai={   16, {
@@ -147,6 +155,24 @@ static comedi_lrange range_ni_E_ai_611x={ 8, {
        RANGE( -0.5,    0.5     ),
        RANGE( -0.2,    0.2     ),
 }};
+static comedi_lrange range_ni_M_ai_622x={ 4, {
+       RANGE(-10, 10),
+       RANGE(-5, 5),
+       RANGE(-1, 1),
+       RANGE(-0.2, 0.2),
+}};
+static comedi_lrange range_ni_M_ai_628x={ 7, {
+       RANGE( -10,     10      ),
+       RANGE( -5,      5       ),
+       RANGE( -2,      2       ),
+       RANGE( -1,      1       ),
+       RANGE( -0.5,    0.5     ),
+       RANGE( -0.2,    0.2     ),
+       RANGE( -0.1,    0.1     ),
+}};
+static comedi_lrange range_ni_S_ai_6143 = { 1, {
+       RANGE( -5,      +5      ),
+}};
 static comedi_lrange range_ni_E_ao_ext = { 4, {
        RANGE( -10,     10      ),
        RANGE( 0,       10      ),
@@ -160,6 +186,9 @@ static comedi_lrange *ni_range_lkup[]={
        &range_ni_E_ai_limited14,
        &range_ni_E_ai_bipolar4,
        &range_ni_E_ai_611x,
+       &range_ni_M_ai_622x,
+       &range_ni_M_ai_628x,
+       &range_ni_S_ai_6143
 };
 
 
@@ -183,11 +212,20 @@ static int ni_calib_insn_write(comedi_device *dev,comedi_subdevice *s,
 
 static int ni_eeprom_insn_read(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data);
+static int ni_m_series_eeprom_insn_read(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data);
 
 static int ni_pfi_insn_bits(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data);
 static int ni_pfi_insn_config(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data);
+static unsigned ni_old_get_pfi_routing(comedi_device *dev, unsigned chan);
+
+static void ni_rtsi_init(comedi_device *dev);
+static int ni_rtsi_insn_bits(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data);
+static int ni_rtsi_insn_config(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data);
 
 static void caldac_setup(comedi_device *dev,comedi_subdevice *s);
 static int ni_read_eeprom(comedi_device *dev,int addr);
@@ -222,28 +260,15 @@ static int ni_ao_reset(comedi_device *dev,comedi_subdevice *s);
 
 static int ni_8255_callback(int dir,int port,int data,unsigned long arg);
 
-static int ni_ns_to_timer(int *nanosec,int round_mode);
-
-
-/*GPCT function def's*/
-static int GPCT_G_Watch(comedi_device *dev, int chan);
-
-static void GPCT_Reset(comedi_device *dev, int chan);
-static void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length);
-static void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length);
-static void GPCT_Period_Meas(comedi_device *dev, int chan);
-static void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan);
-static void GPCT_Event_Counting(comedi_device *dev,int chan);
-static int GPCT_Set_Direction(comedi_device *dev,int chan,int direction);
-static int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate);
-static int GPCT_Set_Source(comedi_device *dev,int chan ,int source);
-
 static int ni_gpct_insn_write(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data);
 static int ni_gpct_insn_read(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data);
 static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data);
+static int ni_gpct_cmd(comedi_device *dev,comedi_subdevice *s);
+static int ni_gpct_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd);
+static int ni_gpct_cancel(comedi_device *dev,comedi_subdevice *s);
 
 static int init_cs5529(comedi_device *dev);
 static int cs5529_do_conversion(comedi_device *dev, unsigned short *data);
@@ -251,6 +276,13 @@ static int cs5529_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_ins
 static unsigned int cs5529_config_read(comedi_device *dev, unsigned int reg_select_bits);
 static void cs5529_config_write(comedi_device *dev, unsigned int value, unsigned int reg_select_bits);
 
+static int ni_m_series_pwm_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data);
+static int ni_6143_pwm_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data);
+
+static int ni_set_master_clock(comedi_device *dev, unsigned source, unsigned period_ns);
+
 enum aimodes
 {
        AIMODE_NONE = 0,
@@ -266,21 +298,214 @@ enum aimodes
 
 static const int num_adc_stages_611x = 3;
 
-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,
-       unsigned int m_status);
+static void handle_a_interrupt(comedi_device *dev, unsigned short status,
+       unsigned ai_mite_status, unsigned gpct0_mite_status);
+static void handle_b_interrupt(comedi_device *dev, unsigned short status,
+       unsigned ao_mite_status, unsigned gpct1_mite_status);
 static void get_last_sample_611x( comedi_device *dev );
+static void get_last_sample_6143( comedi_device *dev );
 #ifdef PCIDMA
 //static void mite_handle_interrupt(comedi_device *dev,unsigned int status);
 static int ni_ai_drain_dma(comedi_device *dev );
+
+/* DMA channel setup */
+
+// negative channel means no channel
+static inline void ni_set_ai_dma_channel(comedi_device *dev, int channel)
+{
+       unsigned long flags;
+
+       comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+       devpriv->ai_ao_select_reg &= ~AI_DMA_Select_Mask;
+       if(channel >= 0)
+       {
+               devpriv->ai_ao_select_reg |= (ni_stc_dma_channel_select_bitfield(channel) << AI_DMA_Select_Shift) & AI_DMA_Select_Mask;
+       }
+       ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
+       mmiowb();
+       comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+}
+
+// negative channel means no channel
+static inline void ni_set_ao_dma_channel(comedi_device *dev, int channel)
+{
+       unsigned long flags;
+
+       comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+       devpriv->ai_ao_select_reg &= ~AO_DMA_Select_Mask;
+       if(channel >= 0)
+       {
+               devpriv->ai_ao_select_reg |= (ni_stc_dma_channel_select_bitfield(channel) << AO_DMA_Select_Shift) & AO_DMA_Select_Mask;
+       }
+       ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
+       mmiowb();
+       comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+}
+
+// negative mite_channel means no channel
+static inline void ni_set_gpct_dma_channel(comedi_device *dev, unsigned gpct_index, int mite_channel)
+{
+       unsigned long flags;
+
+       comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+       devpriv->g0_g1_select_reg &= ~GPCT_DMA_Select_Mask(gpct_index);
+       if(mite_channel >= 0)
+       {
+               devpriv->g0_g1_select_reg |= GPCT_DMA_Select_Bits(gpct_index, mite_channel);
+       }
+       ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select);
+       mmiowb();
+       comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+}
+
+static int ni_request_ai_mite_channel(comedi_device *dev)
+{
+       unsigned long flags;
+
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       BUG_ON(devpriv->ai_mite_chan);
+       devpriv->ai_mite_chan = mite_request_channel(devpriv->mite, devpriv->ai_mite_ring);
+       if(devpriv->ai_mite_chan == NULL)
+       {
+               comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+               comedi_error(dev, "failed to reserve mite dma channel for analog input.");
+               return -EBUSY;
+       }
+       ni_set_ai_dma_channel(dev, devpriv->ai_mite_chan->channel);
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+       return 0;
+}
+
+static int ni_request_ao_mite_channel(comedi_device *dev)
+{
+       unsigned long flags;
+
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       BUG_ON(devpriv->ao_mite_chan);
+       devpriv->ao_mite_chan = mite_request_channel(devpriv->mite, devpriv->ao_mite_ring);
+       if(devpriv->ao_mite_chan == NULL)
+       {
+               comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+               comedi_error(dev, "failed to reserve mite dma channel for analog outut.");
+               return -EBUSY;
+       }
+       ni_set_ao_dma_channel(dev, devpriv->ao_mite_chan->channel);
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+       return 0;
+}
+
+static int ni_request_gpct_mite_channel(comedi_device *dev, unsigned gpct_index)
+{
+       unsigned long flags;
+
+       BUG_ON(gpct_index >= NUM_GPCT);
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       BUG_ON(devpriv->gpct_mite_chan[gpct_index]);
+       devpriv->gpct_mite_chan[gpct_index] = mite_request_channel(devpriv->mite, devpriv->gpct_mite_ring[gpct_index]);
+       if(devpriv->gpct_mite_chan[gpct_index] == NULL)
+       {
+               comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+               comedi_error(dev, "failed to reserve mite dma channel for counter.");
+               return -EBUSY;
+       }
+       ni_set_gpct_dma_channel(dev, gpct_index, devpriv->gpct_mite_chan[gpct_index]->channel);
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+       return 0;
+}
+
+#endif // PCIDMA
+
+static void ni_release_ai_mite_channel(comedi_device *dev)
+{
+#ifdef PCIDMA
+       unsigned long flags;
+
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       if(devpriv->ai_mite_chan)
+       {
+               ni_set_ai_dma_channel(dev, -1);
+               mite_dma_disarm(devpriv->ai_mite_chan);
+               mite_dma_reset(devpriv->ai_mite_chan);
+               mite_release_channel(devpriv->ai_mite_chan);
+               devpriv->ai_mite_chan = NULL;
+       }
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+#endif // PCIDMA
+}
+
+static void ni_release_ao_mite_channel(comedi_device *dev)
+{
+#ifdef PCIDMA
+       unsigned long flags;
+
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       if(devpriv->ao_mite_chan)
+       {
+               ni_set_ao_dma_channel(dev, -1);
+               mite_dma_disarm(devpriv->ao_mite_chan);
+               mite_dma_reset(devpriv->ao_mite_chan);
+               mite_release_channel(devpriv->ao_mite_chan);
+               devpriv->ao_mite_chan = NULL;
+       }
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+#endif // PCIDMA
+}
+
+void ni_release_gpct_mite_channel(comedi_device *dev, unsigned gpct_index)
+{
+#ifdef PCIDMA
+       unsigned long flags;
+
+       BUG_ON(gpct_index >= NUM_GPCT);
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       if(devpriv->gpct_mite_chan[gpct_index])
+       {
+               ni_set_gpct_dma_channel(dev, gpct_index, -1);
+               mite_dma_disarm(devpriv->gpct_mite_chan[gpct_index]);
+               mite_dma_reset(devpriv->gpct_mite_chan[gpct_index]);
+               mite_release_channel(devpriv->gpct_mite_chan[gpct_index]);
+               devpriv->gpct_mite_chan[gpct_index] = NULL;
+       }
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+#endif // PCIDMA
+}
+
+static void ni_clear_ai_fifo(comedi_device *dev){
+       if(boardtype.reg_type == ni_reg_6143){
+               // Flush the 6143 data FIFO
+               ni_writel(0x10, AIFIFO_Control_6143);           // Flush fifo
+               ni_writel(0x00, AIFIFO_Control_6143);           // Flush fifo
+               while(ni_readl(AIFIFO_Status_6143) & 0x10);     // Wait for complete
+       }else {
+               devpriv->stc_writew(dev, 1,ADC_FIFO_Clear);
+               if(boardtype.reg_type == ni_reg_625x)
+               {
+                       ni_writeb(0, M_Offset_Static_AI_Control(0));
+                       ni_writeb(1, M_Offset_Static_AI_Control(0));
+#if 0
+               /* the NI example code does 3 convert pulses for 625x boards,
+               but that appears to be wrong in practice. */
+                       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+                       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+                       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
 #endif
+               }
+       }
+}
 
-#define win_out2(data,addr) do{ \
-       win_out((data)>>16, (addr)); \
-       win_out((data)&0xffff, (addr)+1); \
-}while(0)
+static void win_out2(comedi_device *dev, uint32_t data, int reg)
+{
+       devpriv->stc_writew(dev, data >> 16, reg);
+       devpriv->stc_writew(dev, data & 0xffff, reg + 1);
+}
 
+static uint32_t win_in2(comedi_device *dev, int reg)
+{
+       uint32_t bits;
+       bits = devpriv->stc_readw(dev, reg) << 16;
+       bits |= devpriv->stc_readw(dev, reg + 1);
+       return bits;
+}
 
 #define ao_win_out(data,addr) ni_ao_win_outw(dev,data,addr)
 static inline void ni_ao_win_outw( comedi_device *dev, uint16_t data, int addr )
@@ -329,212 +554,143 @@ static inline void ni_set_bits(comedi_device *dev, int reg, int bits, int value)
 {
        unsigned long flags;
 
-       comedi_spin_lock_irqsave( &devpriv->window_lock, flags );
+       comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
        switch (reg){
                case Interrupt_A_Enable_Register:
                        if(value)
                                devpriv->int_a_enable_reg |= bits;
                        else
                                devpriv->int_a_enable_reg &= ~bits;
-                       comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags );
-                       win_out(devpriv->int_a_enable_reg,Interrupt_A_Enable_Register);
+                       devpriv->stc_writew(dev, devpriv->int_a_enable_reg,Interrupt_A_Enable_Register);
                        break;
                case Interrupt_B_Enable_Register:
                        if(value)
                                devpriv->int_b_enable_reg |= bits;
                        else
                                devpriv->int_b_enable_reg &= ~bits;
-                       comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags );
-                       win_out(devpriv->int_b_enable_reg,Interrupt_B_Enable_Register);
+                       devpriv->stc_writew(dev, devpriv->int_b_enable_reg,Interrupt_B_Enable_Register);
                        break;
                case IO_Bidirection_Pin_Register:
                        if(value)
                                devpriv->io_bidirection_pin_reg |= bits;
                        else
                                devpriv->io_bidirection_pin_reg &= ~bits;
-                       comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags );
-                       win_out(devpriv->io_bidirection_pin_reg,IO_Bidirection_Pin_Register);
+                       devpriv->stc_writew(dev, devpriv->io_bidirection_pin_reg,IO_Bidirection_Pin_Register);
                        break;
                default:
-                       printk("Warning ni_set_bits() called with invalid arguments\n");
-                       printk("reg is %d\n",reg);
-                       comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags );
+                       rt_printk("Warning ni_set_bits() called with invalid arguments\n");
+                       rt_printk("reg is %d\n",reg);
                        break;
        }
+       comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags );
 }
 
 
-static irqreturn_t ni_E_interrupt(int irq,void *d,struct pt_regs * regs)
+static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG)
 {
        comedi_device *dev=d;
        unsigned short a_status;
        unsigned short b_status;
-       unsigned int m0_status;
-       unsigned int m1_status;
+       unsigned int ai_mite_status = 0;
+       unsigned int ao_mite_status = 0;
+       unsigned gpct0_mite_status = 0;
+       unsigned gpct1_mite_status = 0;
        unsigned long flags;
-#ifdef PCIDMA
        struct mite_struct *mite = devpriv->mite;
-#endif
+
+       if(dev->attached == 0) return IRQ_NONE;
+       smp_mb();       // make sure dev->attached is checked before handler does anything else.
+
        // lock to avoid race with comedi_poll
        comedi_spin_lock_irqsave(&dev->spinlock, flags);
-       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(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
-
-       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);
+       a_status = devpriv->stc_readw(dev, AI_Status_1_Register);
+       b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
+       if(mite)
+       {
+               unsigned long flags_too;
+
+               comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags_too);
+               if(devpriv->ai_mite_chan)
+                       ai_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->ai_mite_chan->channel));
+               if(devpriv->ao_mite_chan)
+                       ao_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->ao_mite_chan->channel));
+               if(devpriv->gpct_mite_chan[0])
+                       gpct0_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->gpct_mite_chan[0]->channel));
+               if(devpriv->gpct_mite_chan[1])
+                       gpct1_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->gpct_mite_chan[1]->channel));
+               comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags_too);
+       }
+       if((a_status & Interrupt_A_St) || ((ai_mite_status | gpct0_mite_status) & CHSR_INT))
+               handle_a_interrupt(dev, a_status, ai_mite_status, gpct0_mite_status);
+       if((b_status & Interrupt_B_St) || ((ao_mite_status | gpct1_mite_status) & CHSR_INT))
+               handle_b_interrupt(dev, b_status, ao_mite_status, gpct1_mite_status);
        comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
        return IRQ_HANDLED;
 }
 
 #ifdef PCIDMA
-static void ni_sync_ai_dma(struct mite_struct *mite, comedi_device *dev)
+static void ni_sync_ai_dma(comedi_device *dev)
 {
-       int count;
        comedi_subdevice *s = dev->subdevices + 0;
-       comedi_async *async = s->async;
-       unsigned int nbytes, old_alloc_count;
-       unsigned int bytes_per_scan = 2 * async->cmd.chanlist_len;
-
-       old_alloc_count = async->buf_write_alloc_count;
-       // write alloc as much as we can
-       comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
-
-       nbytes = mite_bytes_transferred(mite, AI_DMA_CHAN);
-       if( (int)(nbytes - old_alloc_count) > 0 ){
-               printk("ni_mio_common: DMA overwrite of free area\n");
-               ni_ai_reset(dev,s);
-               async->events |= COMEDI_CB_OVERFLOW;
-               return;
-       }
-
-       count = nbytes - async->buf_write_count;
-       if( count < 0 ){
-               rt_printk("ni_mio_common: BUG: negative ai count\n");
-               return;
-       }
-
-       comedi_buf_write_free(async, count);
+       unsigned long flags;
 
-       async->scan_progress += count;
-       if( async->scan_progress >= bytes_per_scan )
-       {
-               async->scan_progress %= bytes_per_scan;
-               async->events |= COMEDI_CB_EOS;
-       }
-       async->events |= COMEDI_CB_BLOCK;
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       if(devpriv->ai_mite_chan)
+               mite_sync_input_dma(devpriv->ai_mite_chan, s->async);
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
 }
 
 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, new_write_count;
 
-       writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(AO_DMA_CHAN));
+       if(devpriv->ao_mite_chan == NULL) return;
+       writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(devpriv->ao_mite_chan->channel));
 
-       new_write_count = async->buf_write_count;
-
-       nbytes = mite_bytes_read(mite, AO_DMA_CHAN);
-       if( async->cmd.stop_src == TRIG_COUNT &&
-               (int) (nbytes - async->cmd.stop_arg * sizeof( sampl_t ) ) > 0 )
-               nbytes = async->cmd.stop_arg * sizeof( sampl_t );
-       if( (int)(nbytes - devpriv->last_buf_write_count) > 0 ){
-               rt_printk("ni_mio_common: DMA underrun\n");
-               ni_ao_reset(dev,s);
-               async->events |= COMEDI_CB_OVERFLOW;
+       if(mite_sync_output_dma(devpriv->ao_mite_chan, s->async) < 0)
+       {
+               s->async->events |= COMEDI_CB_ERROR;
                return;
        }
-
-       devpriv->last_buf_write_count = new_write_count;
-
-       count = nbytes - async->buf_read_count;
-       if( count < 0 ){
-               rt_printk("ni_mio_common: BUG: negative ao count\n");
-               count = 0;
-       }
-       comedi_buf_read_free(async, count);
-
-       async->events |= COMEDI_CB_BLOCK;
-}
-
-#if 0
-static void mite_handle_interrupt(comedi_device *dev,unsigned int m_status)
-{
-       int len;
-       comedi_subdevice *s = dev->subdevices+0;
-       comedi_async *async = s->async;
-       struct mite_struct *mite = devpriv->mite;
-
-       async->events |= COMEDI_CB_BLOCK;
-
-       MDPRINTK("mite_handle_interrupt: m_status=%08x\n",m_status);
-       if(m_status & CHSR_DONE){
-               writel(CHOR_CLRDONE, mite->mite_io_addr + MITE_CHOR +
-                       CHAN_OFFSET(0));
-       }
-
-#if 0
-       len = sizeof(sampl_t)*async->cmd.stop_arg*async->cmd.scan_end_arg;
-       if((devpriv->mite->DMA_CheckNearEnd) &&
-                       (s->async->buf_int_count > (len - s->async->prealloc_bufsz))) {
-               long offset;
-               int i;
-
-               offset = len % async->prealloc_bufsz;
-               if(offset < mite->ring[0].count) {
-                       mite->ring[0].count = offset;
-                       mite->ring[1].count = 0;
-               }else{
-                       offset -= mite->ring[0].count;
-                       i = offset >> PAGE_SHIFT;
-                       mite->ring[i].count = offset & ~PAGE_MASK;
-                       mite->ring[(i+1)%mite->n_links].count = 0;
-               }
-               mite->DMA_CheckNearEnd = 0;
-       }
-#endif
-
-#if  0
-       MDPRINTK("CHSR is 0x%08x, count is %d\n",m_status,async->buf_int_count);
-       if(m_status&CHSR_DONE){
-               writel(CHOR_CLRDONE, mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(mite->chan));
-               //printk("buf_int_count is %d, buf_int_ptr is %d\n",
-               //              s->async->buf_int_count,s->async->buf_int_ptr);
-               ni_handle_block_dma(dev);
-       }
-       MDPRINTK("exit mite_handle_interrupt\n");
-#endif
-
-       //comedi_event(dev,s,async->events);
 }
-#endif
 
+// #define DEBUG_DMA_TIMING
 static int ni_ao_wait_for_dma_load( comedi_device *dev )
 {
        static const int timeout = 10000;
        int i;
-
+#ifdef DEBUG_DMA_TIMING
+       struct timeval start;
+       do_gettimeofday(&start);
+#endif
        for(i = 0; i < timeout; i++)
        {
                unsigned short b_status;
 
-               b_status = win_in( AO_Status_1_Register );
+               b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
                if( b_status & AO_FIFO_Half_Full_St )
                        break;
                /* if we poll too often, the pci bus activity seems
                 to slow the dma transfer down */
                comedi_udelay(10);
        }
+#ifdef DEBUG_DMA_TIMING
+       rt_printk("looped %i times waiting for ao fifo load.\n", i);
+       struct timeval now;
+       do_gettimeofday(&now);
+       unsigned elapsed_usec = 1000000 * (now.tv_sec - start.tv_sec) + now.tv_usec - start.tv_usec;
+       rt_printk("total elapsed usec=%i\n", elapsed_usec);
+       do_gettimeofday(&start);
+       unsigned b_status;
+       for(i = 0; i < 100; ++i)
+       {
+//             devpriv->stc_writew(dev, devpriv->ao_mode3, AO_Mode_3_Register);
+               b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
+       }
+       do_gettimeofday(&now);
+       elapsed_usec = 1000000 * (now.tv_sec - start.tv_sec) + now.tv_usec - start.tv_usec;
+       rt_printk("usec to do 100 word xfers=%i\n", elapsed_usec);
+#endif
        if( i == timeout )
        {
                comedi_error(dev, "timed out waiting for dma load");
@@ -554,7 +710,7 @@ static void ni_handle_eos(comedi_device *dev, comedi_subdevice *s)
 
                for(i = 0; i < timeout; i++)
                {
-                       ni_sync_ai_dma(devpriv->mite, dev);
+                       ni_sync_ai_dma(dev);
                        if((s->async->events & COMEDI_CB_EOS)) break;
                        comedi_udelay(1);
                }
@@ -564,7 +720,7 @@ static void ni_handle_eos(comedi_device *dev, comedi_subdevice *s)
 #endif
        }
        /* handle special case of single scan using AI_End_On_End_Of_Scan */
-       if( ( devpriv->ai_cmd2 & AI_End_On_End_Of_Scan ) ){
+       if((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)){
                shutdown_ai_command( dev );
        }
 }
@@ -575,54 +731,103 @@ static void shutdown_ai_command( comedi_device *dev )
 
 #ifdef PCIDMA
        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|
-               AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable|
-               AI_FIFO_Interrupt_Enable,0);
+       get_last_sample_6143(dev);
 
        s->async->events |= COMEDI_CB_EOA;
 }
 
-static void handle_a_interrupt(comedi_device *dev,unsigned short status,
-       unsigned int m_status)
+static void handle_gpct_interrupt(comedi_device *dev, struct mite_channel *mite_chan, unsigned short is_terminal_count)
+{
+       unsigned gpct_mite_status;
+
+       gpct_mite_status = readl(mite_chan->mite->mite_io_addr + MITE_CHSR(mite_chan->channel));
+       if(gpct_mite_status & CHSR_INT)
+       {}
+}
+
+static void ni_event(comedi_device *dev, comedi_subdevice *s, unsigned events)
+{
+       if(events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | COMEDI_CB_EOA))
+       {
+               switch(s->type)
+               {
+               case COMEDI_SUBD_AI:
+                       ni_ai_reset(dev, s);
+                       break;
+               case COMEDI_SUBD_AO:
+                       ni_ao_reset(dev, s);
+                       break;
+               default:
+                       break;
+               }
+       }
+       comedi_event(dev, s, events);
+}
+
+static void ack_a_interrupt(comedi_device *dev, unsigned short a_status)
+{
+       unsigned short ack = 0;
+
+       /* test for all uncommon interrupt events at the same time */
+       if(a_status & AI_SC_TC_St)
+       {
+               ack |= AI_SC_TC_Interrupt_Ack;
+       }
+       if(a_status & AI_START1_St)
+       {
+                       ack |= AI_START1_Interrupt_Ack;
+       }
+       if(a_status & AI_START_St)
+       {
+               ack |= AI_START_Interrupt_Ack;
+       }
+       if(a_status & AI_STOP_St)
+       {
+               /* not sure why we used to ack the START here also, instead of doing it independently. Frank Hess 2007-07-06 */
+               ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack*/;
+       }
+       if(a_status & G0_TC_St)
+       {
+               ack |= G0_TC_Interrupt_Ack;
+       }
+       if(a_status & G0_Gate_Interrupt_St)
+       {
+               ack |= G0_Gate_Interrupt_Ack;
+       }
+       if(ack) devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register);
+}
+
+static void handle_a_interrupt(comedi_device *dev, unsigned short status,
+       unsigned ai_mite_status, unsigned gpct0_mite_status)
 {
        comedi_subdevice *s=dev->subdevices+0;
-       //comedi_async *async = s->async;
-       unsigned short ack=0;
 
        s->async->events = 0;
 
 #ifdef DEBUG_INTERRUPT
-       rt_printk("ni_mio_common: interrupt: a_status=%04x m0_status=%08x\n",
-               status, m_status);
+       rt_printk("ni_mio_common: interrupt: a_status=%04x ai_mite_status=%08x\n",
+               status, ai_mite_status);
        ni_mio_print_status_a(status);
 #endif
-
-
+       ack_a_interrupt(dev, status);
 #ifdef PCIDMA
        /* Currently, mite.c requires us to handle LINKC and DONE */
-       if(m_status & CHSR_LINKC){
-               writel(CHOR_CLRLC, devpriv->mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(AI_DMA_CHAN));
-               ni_sync_ai_dma(devpriv->mite, dev);
+       if(ai_mite_status & CHSR_LINKC){
+               writel(CHOR_CLRLC, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ai_mite_chan->channel));
+               ni_sync_ai_dma(dev);
        }
 
-       if(m_status & CHSR_DONE){
-               writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR +
-                       CHAN_OFFSET(AI_DMA_CHAN));
+       if(ai_mite_status & CHSR_DONE){
+               writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ai_mite_chan->channel));
        }
 
-       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, AI_DMA_CHAN );
-               writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR +
-                       CHAN_OFFSET(AI_DMA_CHAN));
+       if(ai_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){
+               rt_printk("unknown mite interrupt, ack! (ai_mite_status=%08x)\n", ai_mite_status);
+               //mite_print_chsr(ai_mite_status);
+               s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
                //disable_irq(dev->irq);
        }
 #endif
@@ -635,7 +840,7 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status,
                         * so it's a good idea to be careful. */
                        if(s->subdev_flags&SDF_RUNNING){
                                s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
-                               //comedi_event(dev,s,s->async->events);
+                               ni_event(dev, s, s->async->events);
                        }
                        return;
                }
@@ -644,14 +849,13 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status,
                                status);
                        ni_mio_print_status_a(status);
 
-                       ni_ai_reset(dev,dev->subdevices);
-
-                       win_out(AI_Error_Interrupt_Ack, Interrupt_A_Ack_Register);
-
                        shutdown_ai_command( dev );
 
                        s->async->events |= COMEDI_CB_ERROR;
-                       comedi_event(dev,s,s->async->events);
+                       if(status & (AI_Overrun_St | AI_Overflow_St))
+                               s->async->events |= COMEDI_CB_OVERFLOW;
+
+                       ni_event(dev, s, s->async->events);
 
                        return;
                }
@@ -660,86 +864,128 @@ static void handle_a_interrupt(comedi_device *dev,unsigned short status,
                        rt_printk("ni_mio_common: SC_TC interrupt\n");
 #endif
                        if(!devpriv->ai_continuous){
-                               shutdown_ai_command( dev );
+                               shutdown_ai_command(dev);
                        }
-                       ack|=AI_SC_TC_Interrupt_Ack;
-               }
-               if(status&AI_START1_St){
-                       ack|=AI_START1_Interrupt_Ack;
                }
        }
 #ifndef PCIDMA
        if(status&AI_FIFO_Half_Full_St){
-               ni_handle_fifo_half_full(dev);
+               int i;
+               static const int timeout = 10;
+               /* pcmcia cards (at least 6036) seem to stop producing interrupts if we
+                *fail to get the fifo less than half full, so loop to be sure.*/
+               for(i = 0; i < timeout; ++i)
+               {
+                       ni_handle_fifo_half_full(dev);
+                       if((devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Half_Full_St) == 0)
+                               break;
+               }
        }
 #endif // !PCIDMA
 
        if( (status & AI_STOP_St) ){
                ni_handle_eos(dev, s);
-               /* we need to ack the START, also */
-               ack |= AI_STOP_Interrupt_Ack|AI_START_Interrupt_Ack;
        }
-#if 0
-       if(devpriv->aimode==AIMODE_SAMPLE){
-               ni_handle_fifo_dregs(dev);
 
-               //s->async->events |= COMEDI_CB_SAMPLE;
+       if(status & (G0_TC_St | G0_Gate_Interrupt_St))
+       {
+               unsigned long flags;
+
+               comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+               if(devpriv->gpct_mite_chan)
+                       handle_gpct_interrupt(dev, devpriv->gpct_mite_chan[0], (status & G0_TC_St));
+               comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
        }
-#endif
-       if(ack) win_out(ack,Interrupt_A_Ack_Register);
 
-       comedi_event(dev,s,s->async->events);
+       ni_event(dev,s,s->async->events);
 
 #ifdef DEBUG_INTERRUPT
-       status=win_in(AI_Status_1_Register);
+       status=devpriv->stc_readw(dev, AI_Status_1_Register);
        if(status&Interrupt_A_St){
-               printk("handle_a_interrupt: BUG, didn't clear interrupt. disabling.\n");
-                win_out(0,Interrupt_Control_Register);
+               rt_printk("handle_a_interrupt: didn't clear interrupt? status=0x%x\n", status);
        }
 #endif
 }
 
-static void handle_b_interrupt(comedi_device *dev,unsigned short b_status, unsigned int m_status)
+static void ack_b_interrupt(comedi_device *dev, unsigned short b_status)
+{
+       unsigned short ack = 0;
+       if(b_status & AO_BC_TC_St)
+       {
+               ack |= AO_BC_TC_Interrupt_Ack;
+       }
+       if(b_status & AO_Overrun_St)
+       {
+               ack |= AO_Error_Interrupt_Ack;
+       }
+       if(b_status & AO_START_St)
+       {
+               ack |= AO_START_Interrupt_Ack;
+       }
+       if(b_status & AO_START1_St)
+       {
+               ack |= AO_START1_Interrupt_Ack;
+       }
+       if(b_status & AO_UC_TC_St)
+       {
+               ack |= AO_UC_TC_Interrupt_Ack;
+       }
+       if(b_status & AO_UI2_TC_St)
+       {
+               ack |= AO_UI2_TC_Interrupt_Ack;
+       }
+       if(b_status & AO_UPDATE_St)
+       {
+               ack |= AO_UPDATE_Interrupt_Ack;
+       }
+       if(b_status & G1_Gate_Interrupt_St)
+       {
+               ack |= G1_Gate_Interrupt_Ack;
+       }
+       if(b_status & G1_TC_St)
+       {
+               ack |= G1_TC_Interrupt_Ack;
+       }
+       if(ack) devpriv->stc_writew(dev, ack, Interrupt_B_Ack_Register);
+}
+
+static void handle_b_interrupt(comedi_device *dev, unsigned short b_status,
+       unsigned ao_mite_status, unsigned gpct1_mite_status)
 {
        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);
+               b_status,ao_mite_status);
        ni_mio_print_status_b(b_status);
 #endif
-
+       ack_b_interrupt(dev, b_status);
 
 #ifdef PCIDMA
        /* Currently, mite.c requires us to handle LINKC and DONE */
-       if(m_status & CHSR_LINKC){
+       if(ao_mite_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(ao_mite_status & CHSR_DONE){
+               writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ao_mite_chan->channel));
        }
 
-       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));
-       }
+       if(ao_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){
+               rt_printk("unknown mite interrupt, ack! (ao_mite_status=%08x)\n", ao_mite_status);
+               //mite_print_chsr(ao_mite_status);
+               s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+       }
 #endif
 
        if(b_status==0xffff)return;
        if(b_status&AO_Overrun_St){
-               rt_printk("ni_mio_common: AO FIFO underrun status=0x%04x status2=0x%04x\n",b_status,win_in(AO_Status_2_Register));
-               ni_ao_reset(dev,s);
+               rt_printk("ni_mio_common: AO FIFO underrun status=0x%04x status2=0x%04x\n",b_status,devpriv->stc_readw(dev, AO_Status_2_Register));
                s->async->events |= COMEDI_CB_OVERFLOW;
        }
 
        if(b_status&AO_BC_TC_St){
-               MDPRINTK("ni_mio_common: AO BC_TC status=0x%04x status2=0x%04x\n",b_status,win_in(AO_Status_2_Register));
-               ni_ao_reset(dev,s);
+               MDPRINTK("ni_mio_common: AO BC_TC status=0x%04x status2=0x%04x\n",b_status,devpriv->stc_readw(dev, AO_Status_2_Register));
                s->async->events |= COMEDI_CB_EOA;
        }
 
@@ -757,18 +1003,7 @@ static void handle_b_interrupt(comedi_device *dev,unsigned short b_status, unsig
        }
 #endif
 
-       b_status=win_in(AO_Status_1_Register);
-       if(b_status&Interrupt_B_St){
-               if(b_status&AO_FIFO_Request_St){
-                       rt_printk("ni_mio_common: AO buffer underrun\n");
-               }
-               rt_printk("Ack! didn't clear AO interrupt. b_status=0x%04x\n",b_status);
-               ni_set_bits(dev,Interrupt_B_Enable_Register,~0,0);
-               ni_ao_reset(dev,s);
-               s->async->events |= COMEDI_CB_OVERFLOW;
-       }
-
-       comedi_event(dev,s,s->async->events);
+       ni_event(dev,s,s->async->events);
 }
 
 #ifdef DEBUG_STATUS_A
@@ -880,7 +1115,7 @@ static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s)
 {
        int n;
 
-       n = comedi_buf_read_n_available(s);
+       n = comedi_buf_read_n_available(s->async);
        if(n==0){
                s->async->events |= COMEDI_CB_OVERFLOW;
                return 0;
@@ -902,11 +1137,12 @@ static int ni_ao_prep_fifo(comedi_device *dev,comedi_subdevice *s)
        int n;
 
        /* reset fifo */
-       win_out(0,DAC_FIFO_Clear);
-       ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
+       devpriv->stc_writew(dev, 1,DAC_FIFO_Clear);
+       if(boardtype.reg_type & ni_reg_6xxx_mask)
+               ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
 
        /* load some data */
-       n = comedi_buf_read_n_available(s);
+       n = comedi_buf_read_n_available(s->async);
        if(n==0)return 0;
 
        n /= sizeof(sampl_t);
@@ -941,7 +1177,26 @@ static void ni_ai_fifo_read(comedi_device *dev,comedi_subdevice *s,
                        data[0] = dl & 0xffff;
                        cfc_write_to_buffer(s, data[0]);
                }
-       }else{
+       } else if(boardtype.reg_type == ni_reg_6143){
+               sampl_t data[2];
+               u32     dl;
+
+               // This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed
+               for(i = 0; i < n / 2; i++){
+                       dl = ni_readl(AIFIFO_Data_6143);
+
+                       data[0] = (dl >> 16) & 0xffff;
+                       data[1] = dl & 0xffff;
+                       cfc_write_array_to_buffer(s, data, sizeof(data));
+               }
+               if(n % 2){
+                       /* Assume there is a single sample stuck in the FIFO */
+                       ni_writel(0x01, AIFIFO_Control_6143);   // Get stranded sample into FIFO
+                       dl = ni_readl(AIFIFO_Data_6143);
+                       data[0] = (dl >> 16) & 0xffff;
+                       cfc_write_to_buffer(s, data[0]);
+               }
+       } else{
                if( n > sizeof(devpriv->ai_fifo_buffer) / sizeof(devpriv->ai_fifo_buffer[0]))
                {
                        comedi_error( dev, "bug! ai_fifo_buffer too small" );
@@ -970,24 +1225,26 @@ static void ni_handle_fifo_half_full(comedi_device *dev)
 #ifdef PCIDMA
 static int ni_ai_drain_dma(comedi_device *dev )
 {
-       struct mite_struct *mite = devpriv->mite;
        int i;
        static const int timeout = 10000;
 
+       if(devpriv->ai_mite_chan == NULL) return 0;
        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 )
+               if((devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Empty_St) &&
+                       mite_bytes_in_transit(devpriv->ai_mite_chan) == 0)
                        break;
                comedi_udelay(2);
        }
-       if( i == timeout )
+       if(i == timeout)
        {
-               rt_printk( "ni_mio_common: wait for dma drain timed out\n" );
+               rt_printk("ni_mio_common: wait for dma drain timed out\n");
+               rt_printk("mite_bytes_in_transit=%i, AI_Status1_Register=0x%x\n",
+                       mite_bytes_in_transit(devpriv->ai_mite_chan), devpriv->stc_readw(dev, AI_Status_1_Register));
                return -1;
        }
 
-       ni_sync_ai_dma( mite, dev );
+       ni_sync_ai_dma(dev);
 
        return 0;
 }
@@ -1004,7 +1261,7 @@ static void ni_handle_fifo_dregs(comedi_device *dev)
        int i;
 
        if(boardtype.reg_type == ni_reg_611x){
-               while((win_in(AI_Status_1_Register)&AI_FIFO_Empty_St) == 0){
+               while((devpriv->stc_readw(dev, 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 */
@@ -1012,13 +1269,32 @@ static void ni_handle_fifo_dregs(comedi_device *dev)
                        data[1] = (dl&0xffff);
                        cfc_write_array_to_buffer(s, data, sizeof(data));
                }
+       }else if(boardtype.reg_type == ni_reg_6143){
+               i = 0;
+               while(ni_readl(AIFIFO_Status_6143) & 0x04){
+                       dl = ni_readl(AIFIFO_Data_6143);
+
+                       /* This may get the hi/lo data in the wrong order */
+                       data[0] = (dl >> 16);
+                       data[1] = (dl & 0xffff);
+                       cfc_write_array_to_buffer(s, data, sizeof(data));
+                       i += 2;
+               }
+               // Check if stranded sample is present
+               if(ni_readl(AIFIFO_Status_6143) & 0x01){
+                       ni_writel(0x01, AIFIFO_Control_6143);   // Get stranded sample into FIFO
+                       dl = ni_readl(AIFIFO_Data_6143);
+                       data[0] = (dl >> 16) & 0xffff;
+                       cfc_write_to_buffer(s, data[0]);
+               }
+
        }else{
-               fifo_empty = win_in(AI_Status_1_Register) & AI_FIFO_Empty_St;
+               fifo_empty = devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Empty_St;
                while(fifo_empty == 0)
                {
                        for(i = 0; i < sizeof(devpriv->ai_fifo_buffer) / sizeof(devpriv->ai_fifo_buffer[0]); i++)
                        {
-                               fifo_empty = win_in(AI_Status_1_Register) & AI_FIFO_Empty_St;
+                               fifo_empty = devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Empty_St;
                                if(fifo_empty) break;
                                devpriv->ai_fifo_buffer[i] = ni_readw(ADC_FIFO_Data_Register);
                        }
@@ -1044,20 +1320,45 @@ static void get_last_sample_611x( comedi_device *dev )
        }
 }
 
+static void get_last_sample_6143(comedi_device* dev)
+{
+       comedi_subdevice*       s = dev->subdevices + 0;
+       sampl_t                 data;
+       u32                     dl;
+
+       if(boardtype.reg_type != ni_reg_6143) return;
+
+       /* Check if there's a single sample stuck in the FIFO */
+       if(ni_readl(AIFIFO_Status_6143) & 0x01){
+               ni_writel(0x01, AIFIFO_Control_6143);   // Get stranded sample into FIFO
+               dl = ni_readl(AIFIFO_Data_6143);
+
+               /* This may get the hi/lo data in the wrong order */
+               data = (dl >> 16) & 0xffff;
+               cfc_write_to_buffer(s, data);
+       }
+}
+
 static void ni_ai_munge(comedi_device *dev, comedi_subdevice *s,
        void *data, unsigned int num_bytes, unsigned int chan_index )
 {
        comedi_async *async = s->async;
        unsigned int i;
-       unsigned int length = num_bytes / sizeof( sampl_t );
+       unsigned int length = num_bytes / bytes_per_sample(s);
        sampl_t *array = data;
-
+       lsampl_t *larray = data;
        for(i = 0; i < length; i++)
        {
 #ifdef PCIDMA
-               array[i] = le16_to_cpu(array[i]);
+               if(s->subdev_flags & SDF_LSAMPL)
+                       larray[i] = le32_to_cpu(larray[i]);
+               else
+                       array[i] = le16_to_cpu(array[i]);
 #endif
-               array[i] += devpriv->ai_offset[ chan_index ];
+               if(s->subdev_flags & SDF_LSAMPL)
+                       larray[i] += devpriv->ai_offset[chan_index];
+               else
+                       array[i] += devpriv->ai_offset[chan_index];
                chan_index++;
                chan_index %= async->cmd.chanlist_len;
        }
@@ -1065,43 +1366,62 @@ static void ni_ai_munge(comedi_device *dev, comedi_subdevice *s,
 
 #ifdef PCIDMA
 
-static void ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd)
+static int ni_ai_setup_MITE_dma(comedi_device *dev)
 {
-       struct mite_struct *mite = devpriv->mite;
-       struct mite_channel *mite_chan = &mite->channels[ AI_DMA_CHAN ];
        comedi_subdevice *s = dev->subdevices + 0;
+       int retval;
+
+       retval = ni_request_ai_mite_channel(dev);
+       if(retval) return retval;
+//     rt_printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel);
 
        /* write alloc the entire buffer */
        comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
 
-       mite_chan->current_link = 0;
-       mite_chan->dir = COMEDI_INPUT;
-       if(boardtype.reg_type == ni_reg_611x)
-               mite_prep_dma(mite, AI_DMA_CHAN, 32, 16);
-       else
-               mite_prep_dma(mite, AI_DMA_CHAN, 16, 16);
-
+       devpriv->ai_mite_chan->dir = COMEDI_INPUT;
+       switch(boardtype.reg_type)
+       {
+       case ni_reg_611x:
+       case ni_reg_6143:
+               mite_prep_dma(devpriv->ai_mite_chan, 32, 16);
+               break;
+       case ni_reg_628x:
+               mite_prep_dma(devpriv->ai_mite_chan, 32, 32);
+               break;
+       default:
+               mite_prep_dma(devpriv->ai_mite_chan, 16, 16);
+               break;
+       };
        /*start the MITE*/
-       mite_dma_arm(mite, AI_DMA_CHAN);
+       mite_dma_arm(devpriv->ai_mite_chan);
+       return 0;
 }
 
-static void ni_ao_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd)
+static int ni_ao_setup_MITE_dma(comedi_device *dev)
 {
-       struct mite_struct *mite = devpriv->mite;
-       struct mite_channel *mite_chan = &mite->channels[ AO_DMA_CHAN ];
        comedi_subdevice *s = dev->subdevices + 1;
+       int retval;
 
-       devpriv->last_buf_write_count = s->async->buf_write_count;
+       retval = ni_request_ao_mite_channel(dev);
+       if(retval) return retval;
+       //rt_printk("comedi_debug: using mite channel %i for ao.\n", devpriv->ao_mite_chan->channel);
 
-       mite_chan->current_link = 0;
-       mite_chan->dir = COMEDI_OUTPUT;
-       if(boardtype.reg_type & (ni_reg_611x | ni_reg_6713))
-               mite_prep_dma(mite, AO_DMA_CHAN, 32, 32);
-       else
-               mite_prep_dma(mite, AO_DMA_CHAN, 16, 16);
+       /* read alloc the entire buffer */
+       comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz);
 
+       devpriv->ao_mite_chan->dir = COMEDI_OUTPUT;
+       if(boardtype.reg_type & (ni_reg_611x | ni_reg_6713))
+       {
+               mite_prep_dma(devpriv->ao_mite_chan, 32, 32);
+       }else
+       {
+               /* doing 32 instead of 16 bit wide transfers from memory
+                makes the mite do 32 bit pci transfers, doubling pci bandwidth. */
+               mite_prep_dma(devpriv->ao_mite_chan, 16, 32);
+       }
        /*start the MITE*/
-       mite_dma_arm(mite, AO_DMA_CHAN);
+       mite_dma_arm(devpriv->ao_mite_chan);
+       return 0;
 }
 
 #endif // PCIDMA
@@ -1114,11 +1434,9 @@ static void ni_ao_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, AI_DMA_CHAN);
-#endif
+       ni_release_ai_mite_channel(dev);
        /* ai configuration */
-       win_out(AI_Configuration_Start | AI_Reset, Joint_Reset_Register);
+       devpriv->stc_writew(dev, AI_Configuration_Start | AI_Reset, Joint_Reset_Register);
 
        ni_set_bits(dev, Interrupt_A_Enable_Register,
                AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|
@@ -1126,37 +1444,51 @@ static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s)
                AI_STOP_Interrupt_Enable|   AI_Error_Interrupt_Enable|
                AI_FIFO_Interrupt_Enable,0);
 
-       win_out(1,ADC_FIFO_Clear);
+       ni_clear_ai_fifo(dev);
 
-       ni_writeb(0, Misc_Command);
+       if(boardtype.reg_type != ni_reg_6143)
+               ni_writeb(0, Misc_Command);
 
-       win_out(AI_Disarm, AI_Command_1_Register); /* reset pulses */
-       win_out(AI_Start_Stop | AI_Mode_1_Reserved /*| AI_Trigger_Once */,
+       devpriv->stc_writew(dev, AI_Disarm, AI_Command_1_Register); /* reset pulses */
+       devpriv->stc_writew(dev, AI_Start_Stop | AI_Mode_1_Reserved /*| AI_Trigger_Once */,
                AI_Mode_1_Register);
-       win_out(0x0000,AI_Mode_2_Register);
+       devpriv->stc_writew(dev, 0x0000,AI_Mode_2_Register);
        /* generate FIFO interrupts on non-empty */
-       win_out((0<<6)|0x0000,AI_Mode_3_Register);
-       if(boardtype.reg_type == ni_reg_normal){
-               win_out(AI_SHIFTIN_Pulse_Width |
+       devpriv->stc_writew(dev, (0<<6)|0x0000,AI_Mode_3_Register);
+       if(boardtype.reg_type == ni_reg_611x){
+               devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
                        AI_SOC_Polarity |
-                       AI_CONVERT_Pulse_Width |
                        AI_LOCALMUX_CLK_Pulse_Width, AI_Personal_Register);
-               win_out(AI_SCAN_IN_PROG_Output_Select(3) |
+               devpriv->stc_writew(dev, AI_SCAN_IN_PROG_Output_Select(3) |
                        AI_EXTMUX_CLK_Output_Select(0) |
                        AI_LOCALMUX_CLK_Output_Select(2) |
                        AI_SC_TC_Output_Select(3) |
-                       AI_CONVERT_Output_Select(2),AI_Output_Control_Register);
-       }else{/* 611x boards */
-               win_out(AI_SHIFTIN_Pulse_Width |
+                       AI_CONVERT_Output_Select(AI_CONVERT_Output_Enable_High), AI_Output_Control_Register);
+       }else if(boardtype.reg_type == ni_reg_6143){
+               devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
                        AI_SOC_Polarity |
                        AI_LOCALMUX_CLK_Pulse_Width, AI_Personal_Register);
-               win_out(AI_SCAN_IN_PROG_Output_Select(3) |
+               devpriv->stc_writew(dev, AI_SCAN_IN_PROG_Output_Select(3) |
                        AI_EXTMUX_CLK_Output_Select(0) |
                        AI_LOCALMUX_CLK_Output_Select(2) |
                        AI_SC_TC_Output_Select(3) |
-                       AI_CONVERT_Output_Select(3),AI_Output_Control_Register);
+                       AI_CONVERT_Output_Select(AI_CONVERT_Output_Enable_Low),AI_Output_Control_Register);
+       }else{
+               unsigned ai_output_control_bits;
+               devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
+                       AI_SOC_Polarity |
+                       AI_CONVERT_Pulse_Width |
+                       AI_LOCALMUX_CLK_Pulse_Width, AI_Personal_Register);
+               ai_output_control_bits = AI_SCAN_IN_PROG_Output_Select(3) |
+                       AI_EXTMUX_CLK_Output_Select(0) |
+                       AI_LOCALMUX_CLK_Output_Select(2) |
+                       AI_SC_TC_Output_Select(3);
+               if(boardtype.reg_type == ni_reg_622x)
+                       ai_output_control_bits |= AI_CONVERT_Output_Select(AI_CONVERT_Output_Enable_High);
+               else
+                       ai_output_control_bits |= AI_CONVERT_Output_Select(AI_CONVERT_Output_Enable_Low);
+               devpriv->stc_writew(dev, ai_output_control_bits, AI_Output_Control_Register);
        }
-
        /* the following registers should not be changed, because there
         * are no backup registers in devpriv.  If you want to change
         * any of these, add a backup register and other appropriate code:
@@ -1165,30 +1497,32 @@ static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s)
         *      AI_Personal_Register
         *      AI_Output_Control_Register
        */
-       win_out(AI_SC_TC_Error_Confirm | AI_START_Interrupt_Ack |
+       devpriv->stc_writew(dev, AI_SC_TC_Error_Confirm | AI_START_Interrupt_Ack |
                AI_START2_Interrupt_Ack | AI_START1_Interrupt_Ack |
                AI_SC_TC_Interrupt_Ack | AI_Error_Interrupt_Ack |
                AI_STOP_Interrupt_Ack, Interrupt_A_Ack_Register); /* clear interrupts */
 
-       win_out(AI_Configuration_End,Joint_Reset_Register);
+       devpriv->stc_writew(dev, AI_Configuration_End,Joint_Reset_Register);
 
        return 0;
 }
 
 static int ni_ai_poll(comedi_device *dev,comedi_subdevice *s)
 {
-       unsigned long flags;
+       unsigned long flags = 0;
        int count;
 
        // lock to avoid race with interrupt handler
-       comedi_spin_lock_irqsave(&dev->spinlock, flags);
+       if(in_interrupt() == 0)
+               comedi_spin_lock_irqsave(&dev->spinlock, flags);
 #ifndef PCIDMA
        ni_handle_fifo_dregs(dev);
 #else
-       ni_sync_ai_dma(devpriv->mite, dev);
+       ni_sync_ai_dma(dev);
 #endif
        count = s->async->buf_write_count - s->async->buf_read_count;
-       comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
+       if(in_interrupt() == 0)
+               comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
 
        return count;
 }
@@ -1197,23 +1531,23 @@ static int ni_ai_poll(comedi_device *dev,comedi_subdevice *s)
 static int ni_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
 {
        int i,n;
-       unsigned int mask;
-       unsigned short signbits;
+       const unsigned int mask = (1 << boardtype.adbits) - 1;
+       unsigned signbits;
        unsigned short d;
+       unsigned long dl;
 
        ni_load_channelgain_list(dev,1,&insn->chanspec);
 
-       win_out(1,ADC_FIFO_Clear);
+       ni_clear_ai_fifo(dev);
 
-       mask=(1<<boardtype.adbits)-1;
        signbits=devpriv->ai_offset[0];
        if(boardtype.reg_type == ni_reg_611x){
                for(n=0; n < num_adc_stages_611x; n++){
-                       win_out(AI_CONVERT_Pulse, AI_Command_1_Register);
+                       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
                        comedi_udelay(1);
                }
                for(n=0; n<insn->n; n++){
-                       win_out(AI_CONVERT_Pulse, AI_Command_1_Register);
+                       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
                        /* The 611x has screwy 32-bit FIFOs. */
                        d = 0;
                        for(i=0; i<NI_TIMEOUT; i++){
@@ -1222,7 +1556,7 @@ static int ni_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_insn *i
                                        d = ( ni_readl(ADC_FIFO_Data_611x) >> 16 ) & 0xffff;
                                        break;
                                }
-                               if(!(win_in(AI_Status_1_Register)&AI_FIFO_Empty_St))
+                               if(!(devpriv->stc_readw(dev, AI_Status_1_Register)&AI_FIFO_Empty_St))
                                {
                                        d = ni_readl(ADC_FIFO_Data_611x) & 0xffff;
                                        break;
@@ -1232,28 +1566,141 @@ static int ni_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_insn *i
                                rt_printk("ni_mio_common: timeout in 611x ni_ai_insn_read\n");
                                return -ETIME;
                        }
-                       d += signbits; /* subtle: needs to be short addition */
+                       d += signbits;
                        data[ n ] = d;
                }
+       }else if(boardtype.reg_type == ni_reg_6143){
+               for(n = 0; n < insn->n; n++){
+                       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+
+                       /* The 6143 has 32-bit FIFOs. You need to strobe a bit to move a single 16bit stranded sample into the FIFO */
+                       dl = 0;
+                       for(i = 0; i < NI_TIMEOUT; i++){
+                               if(ni_readl(AIFIFO_Status_6143) & 0x01)
+                               {
+                                       ni_writel(0x01, AIFIFO_Control_6143);   // Get stranded sample into FIFO
+                                       dl = ni_readl(AIFIFO_Data_6143);
+                                       break;
+                               }
+                       }
+                       if(i == NI_TIMEOUT){
+                               rt_printk("ni_mio_common: timeout in 6143 ni_ai_insn_read\n");
+                               return -ETIME;
+                       }
+                       data[n] = (((dl >> 16) & 0xFFFF) + signbits) & 0xFFFF;
+               }
        }else{
-               for(n=0;n<insn->n;n++){
-                       win_out(AI_CONVERT_Pulse, AI_Command_1_Register);
-                       for(i=0;i<NI_TIMEOUT;i++){
-                               if(!(win_in(AI_Status_1_Register)&AI_FIFO_Empty_St))
+               for(n = 0; n < insn->n; n++){
+                       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+                       for(i = 0; i < NI_TIMEOUT; i++){
+                               if(!(devpriv->stc_readw(dev, AI_Status_1_Register)&AI_FIFO_Empty_St))
                                        break;
                        }
-                       if(i==NI_TIMEOUT){
+                       if(i == NI_TIMEOUT){
                                rt_printk("ni_mio_common: timeout in ni_ai_insn_read\n");
                                return -ETIME;
                        }
-                       d = ni_readw(ADC_FIFO_Data_Register);
-                       d += signbits; /* subtle: needs to be short addition */
-                       data[n] = d;
+                       if(boardtype.reg_type & ni_reg_m_series_mask)
+                       {
+                               data[n] = ni_readl(M_Offset_AI_FIFO_Data) & mask;
+                       }else
+                       {
+                               d = ni_readw(ADC_FIFO_Data_Register);
+                               d += signbits; /* subtle: needs to be short addition */
+                               data[n] = d;
+                       }
                }
        }
        return insn->n;
 }
 
+void ni_prime_channelgain_list(comedi_device *dev)
+{
+       int i;
+       devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+       for(i = 0; i < NI_TIMEOUT; ++i)
+       {
+               if(!(devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Empty_St))
+               {
+                       devpriv->stc_writew(dev, 1, ADC_FIFO_Clear);
+                       return;
+               }
+               comedi_udelay(1);
+       }
+       rt_printk("ni_mio_common: timeout loading channel/gain list\n");
+}
+
+static void ni_m_series_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
+       unsigned int *list)
+{
+       unsigned int chan, range, aref;
+       unsigned int i;
+       unsigned offset;
+       unsigned int dither;
+       unsigned range_code;
+
+       devpriv->stc_writew(dev, 1, Configuration_Memory_Clear);
+
+//     offset = 1 << (boardtype.adbits - 1);
+       if((list[0] & CR_ALT_SOURCE))
+       {
+               unsigned bypass_bits;
+               chan = CR_CHAN(list[0]);
+               range = CR_RANGE(list[0]);
+               range_code = ni_gainlkup[boardtype.gainlkup][range];
+               dither = ((list[0] & CR_ALT_FILTER) != 0);
+               bypass_bits = MSeries_AI_Bypass_Config_FIFO_Bit;
+               bypass_bits |= chan;
+               bypass_bits |= (devpriv->ai_calib_source) & (MSeries_AI_Bypass_Cal_Sel_Pos_Mask |
+                       MSeries_AI_Bypass_Cal_Sel_Neg_Mask | MSeries_AI_Bypass_Mode_Mux_Mask |
+                       MSeries_AO_Bypass_AO_Cal_Sel_Mask);
+               bypass_bits |= MSeries_AI_Bypass_Gain_Bits(range_code);
+               if(dither)
+                       bypass_bits |= MSeries_AI_Bypass_Dither_Bit;
+               // don't use 2's complement encoding
+               bypass_bits |= MSeries_AI_Bypass_Polarity_Bit;
+               ni_writel(bypass_bits, M_Offset_AI_Config_FIFO_Bypass);
+       }else
+       {
+               ni_writel(0, M_Offset_AI_Config_FIFO_Bypass);
+       }
+       offset = 0;
+       for(i = 0; i < n_chan; i++)
+       {
+               unsigned config_bits = 0;
+               chan = CR_CHAN(list[i]);
+               aref = CR_AREF(list[i]);
+               range = CR_RANGE(list[i]);
+               dither = ((list[i] & CR_ALT_FILTER) != 0);
+
+               range_code = ni_gainlkup[boardtype.gainlkup][range];
+               devpriv->ai_offset[i] = offset;
+               switch( aref )
+               {
+                       case AREF_DIFF:
+                               config_bits |= MSeries_AI_Config_Channel_Type_Differential_Bits;
+                               break;
+                       case AREF_COMMON:
+                               config_bits |= MSeries_AI_Config_Channel_Type_Common_Ref_Bits;
+                               break;
+                       case AREF_GROUND:
+                               config_bits |= MSeries_AI_Config_Channel_Type_Ground_Ref_Bits;
+                               break;
+                       case AREF_OTHER:
+                               break;
+               }
+               config_bits |= MSeries_AI_Config_Channel_Bits(chan);
+               config_bits |= MSeries_AI_Config_Bank_Bits(chan);
+               config_bits |= MSeries_AI_Config_Gain_Bits(range_code);
+               if(i == n_chan - 1) config_bits |= MSeries_AI_Config_Last_Channel_Bit;
+               if(dither) config_bits |= MSeries_AI_Config_Dither_Bit;
+               // don't use 2's complement encoding
+               config_bits |= MSeries_AI_Config_Polarity_Bit;
+               ni_writew(config_bits, M_Offset_AI_Config_FIFO_Data);
+       }
+       ni_prime_channelgain_list(dev);
+}
+
 /*
  * Notes on the 6110 and 6111:
  * These boards a slightly different than the rest of the series, since
@@ -1289,10 +1736,15 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
        unsigned int chan,range,aref;
        unsigned int i;
        unsigned int hi,lo;
-       unsigned short offset;
+       unsigned offset;
        unsigned int dither;
 
-       if(n_chan == 1 && boardtype.reg_type == ni_reg_normal){
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+       {
+               ni_m_series_load_channelgain_list(dev, n_chan, list);
+               return;
+       }
+       if(n_chan == 1 && (boardtype.reg_type != ni_reg_611x) && (boardtype.reg_type != ni_reg_6143)){
                if(devpriv->changain_state && devpriv->changain_spec==list[0]){
                        // ready to go.
                        return;
@@ -1303,11 +1755,29 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
                devpriv->changain_state=0;
        }
 
-       win_out(1,Configuration_Memory_Clear);
+       devpriv->stc_writew(dev, 1,Configuration_Memory_Clear);
+
+       // Set up Calibration mode if required
+       if(boardtype.reg_type == ni_reg_6143){
+               if((list[0] & CR_ALT_SOURCE) && !devpriv->ai_calib_source_enabled){
+                       // Strobe Relay enable bit
+                       ni_writew(devpriv->ai_calib_source | Calibration_Channel_6143_RelayOn, Calibration_Channel_6143);
+                       ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143);
+                       devpriv->ai_calib_source_enabled = 1;
+                       msleep_interruptible(100);      // Allow relays to change
+               }
+               else if(!(list[0] & CR_ALT_SOURCE) && devpriv->ai_calib_source_enabled){
+                       // Strobe Relay disable bit
+                       ni_writew(devpriv->ai_calib_source | Calibration_Channel_6143_RelayOff, Calibration_Channel_6143);
+                       ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143);
+                       devpriv->ai_calib_source_enabled = 0;
+                       msleep_interruptible(100);      // Allow relays to change
+               }
+       }
 
        offset=1<<(boardtype.adbits-1);
        for(i=0;i<n_chan;i++){
-               if(list[i]&CR_ALT_SOURCE){
+               if((boardtype.reg_type != ni_reg_6143) && (list[i] & CR_ALT_SOURCE)){
                        chan=devpriv->ai_calib_source;
                }else{
                        chan=CR_CHAN(list[i]);
@@ -1332,6 +1802,8 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
                {
                        if(boardtype.reg_type == ni_reg_611x)
                                aref = AREF_DIFF;
+                       else if(boardtype.reg_type == ni_reg_6143)
+                               aref = AREF_OTHER;
                        switch( aref )
                        {
                                case AREF_DIFF:
@@ -1351,50 +1823,59 @@ static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,
 
                ni_writew(hi,Configuration_Memory_High);
 
-               lo = range;
-               if(i == n_chan - 1) lo |= AI_LAST_CHANNEL;
-               if( dither ) lo |= AI_DITHER;
+               if(boardtype.reg_type != ni_reg_6143){
+                       lo = range;
+                       if(i == n_chan - 1) lo |= AI_LAST_CHANNEL;
+                       if( dither ) lo |= AI_DITHER;
 
-               ni_writew(lo,Configuration_Memory_Low);
+                       ni_writew(lo,Configuration_Memory_Low);
+               }
        }
 
        /* prime the channel/gain list */
-       if(boardtype.reg_type == ni_reg_normal){
-               win_out(AI_CONVERT_Pulse, AI_Command_1_Register);
-               for(i=0;i<NI_TIMEOUT;i++){
-                       if(!(win_in(AI_Status_1_Register)&AI_FIFO_Empty_St)){
-                               win_out(1,ADC_FIFO_Clear);
-                               return;
-                       }
-                       comedi_udelay(1);
-               }
-               rt_printk("ni_mio_common: timeout loading channel/gain list\n");
+       if((boardtype.reg_type != ni_reg_611x) && (boardtype.reg_type != ni_reg_6143)){
+               ni_prime_channelgain_list(dev);
        }
 }
 
-#define TIMER_BASE 50 /* 20 Mhz base */
-
-static int ni_ns_to_timer(int *nanosec,int round_mode)
+static int ni_ns_to_timer(const comedi_device *dev, unsigned nanosec, int round_mode)
 {
-       int divider,base;
-
-       base=TIMER_BASE;
-
-       switch(round_mode){
+       int divider;
+       switch(round_mode)
+       {
        case TRIG_ROUND_NEAREST:
        default:
-               divider=(*nanosec+base/2)/base;
+               divider = (nanosec + devpriv->clock_ns / 2) / devpriv->clock_ns;
                break;
        case TRIG_ROUND_DOWN:
-               divider=(*nanosec)/base;
+               divider = (nanosec) / devpriv->clock_ns;
                break;
        case TRIG_ROUND_UP:
-               divider=(*nanosec+base-1)/base;
+               divider=(nanosec + devpriv->clock_ns - 1) / devpriv->clock_ns;
                break;
        }
+       return divider - 1;
+}
+
+static unsigned ni_timer_to_ns(const comedi_device *dev, int timer)
+{
+       return devpriv->clock_ns * (timer + 1);
+}
 
-       *nanosec=base*divider;
-       return divider-1;
+static unsigned ni_min_ai_scan_period_ns(comedi_device *dev, unsigned num_channels)
+{
+       switch(boardtype.reg_type)
+       {
+       case ni_reg_611x:
+       case ni_reg_6143:
+       // simultaneously-sampled inputs
+               return boardtype.ai_speed;
+               break;
+       default:
+       // multiplexed inputs
+               break;
+       };
+       return boardtype.ai_speed * num_channels;
 }
 
 static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
@@ -1415,7 +1896,7 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
 
        tmp=cmd->convert_src;
        sources = TRIG_TIMER | TRIG_EXT;
-       if(boardtype.reg_type == ni_reg_611x) sources |= TRIG_NOW;
+       if((boardtype.reg_type == ni_reg_611x) || (boardtype.reg_type == ni_reg_6143)) sources |= TRIG_NOW;
        cmd->convert_src &= sources;
        if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
 
@@ -1452,10 +1933,9 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                /* external trigger */
                unsigned int tmp = CR_CHAN(cmd->start_arg);
 
-               if(tmp>9)tmp=9;
-               /* XXX for now, use the top bit to invert the signal */
-               tmp |= (cmd->start_arg&0x80000000);
-               if(cmd->start_arg!=tmp){
+               if(tmp > 16) tmp = 16;
+               tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE));
+               if(cmd->start_arg != tmp){
                        cmd->start_arg = tmp;
                        err++;
                }
@@ -1467,21 +1947,21 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                }
        }
        if(cmd->scan_begin_src==TRIG_TIMER){
-               if(cmd->scan_begin_arg<boardtype.ai_speed){
-                       cmd->scan_begin_arg=boardtype.ai_speed;
+               if(cmd->scan_begin_arg < ni_min_ai_scan_period_ns(dev, cmd->chanlist_len))
+               {
+                       cmd->scan_begin_arg = ni_min_ai_scan_period_ns(dev, cmd->chanlist_len);
                        err++;
                }
-               if(cmd->scan_begin_arg>TIMER_BASE*0xffffff){
-                       cmd->scan_begin_arg=TIMER_BASE*0xffffff;
+               if(cmd->scan_begin_arg > devpriv->clock_ns * 0xffffff){
+                       cmd->scan_begin_arg = devpriv->clock_ns * 0xffffff;
                        err++;
                }
        }else if(cmd->scan_begin_src==TRIG_EXT){
                /* external trigger */
                unsigned int tmp = CR_CHAN(cmd->scan_begin_arg);
 
-               if(tmp>9)tmp=9;
-               /* XXX for now, use the top bit to invert the signal */
-               tmp |= (cmd->scan_begin_arg&0x80000000);
+               if(tmp>16)tmp=16;
+               tmp |= (cmd->scan_begin_arg & (CR_INVERT | CR_EDGE));
                if(cmd->scan_begin_arg!=tmp){
                        cmd->scan_begin_arg = tmp;
                        err++;
@@ -1493,7 +1973,7 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                }
        }
        if(cmd->convert_src==TRIG_TIMER){
-               if(boardtype.reg_type == ni_reg_611x){
+               if((boardtype.reg_type == ni_reg_611x) || (boardtype.reg_type == ni_reg_6143)){
                        if(cmd->convert_arg != 0){
                                cmd->convert_arg = 0;
                                err++;
@@ -1503,8 +1983,8 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                                cmd->convert_arg=boardtype.ai_speed;
                                err++;
                        }
-                       if(cmd->convert_arg>TIMER_BASE*0xffff){
-                               cmd->convert_arg=TIMER_BASE*0xffff;
+                       if(cmd->convert_arg>devpriv->clock_ns*0xffff){
+                               cmd->convert_arg=devpriv->clock_ns*0xffff;
                                err++;
                        }
                }
@@ -1512,7 +1992,7 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                /* external trigger */
                unsigned int tmp = CR_CHAN(cmd->convert_arg);
 
-               if(tmp>9)tmp=9;
+               if(tmp>16)tmp=16;
                tmp |= (cmd->convert_arg&(CR_ALT_FILTER|CR_INVERT));
                if(cmd->convert_arg!=tmp){
                        cmd->convert_arg = tmp;
@@ -1538,6 +2018,10 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                        cmd->stop_arg = max_count;
                        err++;
                }
+               if(cmd->stop_arg < 1){
+                       cmd->stop_arg = 1;
+                       err++;
+               }
        }else{
                /* TRIG_NONE */
                if(cmd->stop_arg!=0){
@@ -1552,16 +2036,17 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
 
        if(cmd->scan_begin_src==TRIG_TIMER){
                tmp=cmd->scan_begin_arg;
-               ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
+               cmd->scan_begin_arg = ni_timer_to_ns(dev, ni_ns_to_timer(dev, cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK));
                if(tmp!=cmd->scan_begin_arg)err++;
        }
        if(cmd->convert_src==TRIG_TIMER){
-               if(boardtype.reg_type == ni_reg_normal){
+               if((boardtype.reg_type != ni_reg_611x) && (boardtype.reg_type != ni_reg_6143)){
                        tmp=cmd->convert_arg;
-                       ni_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
+                       cmd->convert_arg = ni_timer_to_ns(dev, ni_ns_to_timer(dev, 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)
+                       {
                                cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg;
                                err++;
                        }
@@ -1575,7 +2060,7 @@ static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
 
 static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
 {
-       comedi_cmd *cmd=&s->async->cmd;
+       const comedi_cmd *cmd=&s->async->cmd;
        int timer;
        int mode1=0; /* mode1 is needed for both stop and convert */
        int mode2=0;
@@ -1584,51 +2069,60 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
        int interrupt_a_enable=0;
 
        MDPRINTK("ni_ai_cmd\n");
-
-       win_out(1,ADC_FIFO_Clear);
+       if(dev->irq == 0)
+       {
+               comedi_error(dev, "cannot run command without an irq");
+               return -EIO;
+       }
+       ni_clear_ai_fifo(dev);
 
        ni_load_channelgain_list(dev,cmd->chanlist_len,cmd->chanlist);
 
        /* start configuration */
-       win_out(AI_Configuration_Start,Joint_Reset_Register);
+       devpriv->stc_writew(dev, AI_Configuration_Start,Joint_Reset_Register);
 
        /* disable analog triggering for now, since it
         * interferes with the use of pfi0 */
        devpriv->an_trig_etc_reg &= ~Analog_Trigger_Enable;
-       win_out(devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
+       devpriv->stc_writew(dev, devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
 
        switch(cmd->start_src){
-       case TRIG_INT:
-       case TRIG_NOW:
-               win_out(AI_START2_Select(0)|
-                       AI_START1_Sync|AI_START1_Edge|AI_START1_Select(0),
-                       AI_Trigger_Select_Register);
-               break;
-       case TRIG_EXT:
-       {
-               int chan = CR_CHAN(cmd->start_arg);
-
-               win_out(AI_START2_Select(0)|
-                       AI_START1_Sync | AI_START1_Edge |
-                       AI_START1_Select(chan + 1),
-                       AI_Trigger_Select_Register);
-               break;
-       }
+               case TRIG_INT:
+               case TRIG_NOW:
+                       devpriv->stc_writew(dev, AI_START2_Select(0)|
+                               AI_START1_Sync|AI_START1_Edge|AI_START1_Select(0),
+                               AI_Trigger_Select_Register);
+                       break;
+               case TRIG_EXT:
+               {
+                       int chan = CR_CHAN(cmd->start_arg);
+                       unsigned int bits = AI_START2_Select(0)|
+                               AI_START1_Sync |
+                               AI_START1_Select(chan + 1);
+
+                       if(cmd->start_arg & CR_INVERT)
+                               bits |= AI_START1_Polarity;
+                       if(cmd->start_arg & CR_EDGE)
+                               bits |= AI_START1_Edge;
+                       devpriv->stc_writew(dev, bits, AI_Trigger_Select_Register);
+                       break;
+               }
        }
 
        mode2 &= ~AI_Pre_Trigger;
        mode2 &= ~AI_SC_Initial_Load_Source;
        mode2 &= ~AI_SC_Reload_Mode;
-       win_out(mode2, AI_Mode_2_Register);
+       devpriv->stc_writew(dev, mode2, AI_Mode_2_Register);
 
-       start_stop_select |= AI_STOP_Sync;
-       if(boardtype.reg_type == ni_reg_611x){
+       if(cmd->chanlist_len == 1 || (boardtype.reg_type == ni_reg_611x) || (boardtype.reg_type == ni_reg_6143)){
                start_stop_select |= AI_STOP_Polarity;
-               start_stop_select |= AI_STOP_Select( 31 );
-       }else{
-               start_stop_select |= AI_STOP_Select( 19 );
+               start_stop_select |= AI_STOP_Select( 31 ); // logic low
+               start_stop_select |= AI_STOP_Sync;
+       }else
+       {
+               start_stop_select |= AI_STOP_Select(19); // ai configuration memory
        }
-       win_out(start_stop_select, AI_START_STOP_Select_Register);
+       devpriv->stc_writew(dev, start_stop_select, AI_START_STOP_Select_Register);
 
        devpriv->ai_cmd2 = 0;
        switch(cmd->stop_src){
@@ -1640,29 +2134,31 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
                        stop_count += num_adc_stages_611x;
                }
                /* stage number of scans */
-               win_out2( stop_count, AI_SC_Load_A_Registers);
+               devpriv->stc_writel(dev,  stop_count, AI_SC_Load_A_Registers);
 
                mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Trigger_Once;
-               win_out(mode1,AI_Mode_1_Register);
+               devpriv->stc_writew(dev, mode1,AI_Mode_1_Register);
                /* load SC (Scan Count) */
-               win_out(AI_SC_Load,AI_Command_1_Register);
+               devpriv->stc_writew(dev, AI_SC_Load,AI_Command_1_Register);
 
                devpriv->ai_continuous = 0;
                if( stop_count == 0 ){
                        devpriv->ai_cmd2 |= AI_End_On_End_Of_Scan;
                        interrupt_a_enable |= AI_STOP_Interrupt_Enable;
+                       // this is required to get the last sample for chanlist_len > 1, not sure why
+                       if(cmd->chanlist_len > 1)
+                               start_stop_select |= AI_STOP_Polarity | AI_STOP_Edge;
                }
                break;
        case TRIG_NONE:
                /* stage number of scans */
-               win_out(0,AI_SC_Load_A_Registers);
-               win_out(0,AI_SC_Load_A_Registers+1);
+               devpriv->stc_writel(dev, 0,AI_SC_Load_A_Registers);
 
                mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;
-               win_out(mode1,AI_Mode_1_Register);
+               devpriv->stc_writew(dev, mode1,AI_Mode_1_Register);
 
                /* load SC (Scan Count) */
-               win_out(AI_SC_Load,AI_Command_1_Register);
+               devpriv->stc_writew(dev, AI_SC_Load,AI_Command_1_Register);
 
                devpriv->ai_continuous = 1;
 
@@ -1686,33 +2182,30 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
                        AI_STOP_Select=19               external pin (configuration mem)
                 */
                start_stop_select |= AI_START_Edge | AI_START_Sync;
-               win_out(start_stop_select, AI_START_STOP_Select_Register);
+               devpriv->stc_writew(dev, start_stop_select, AI_START_STOP_Select_Register);
 
                mode2 |= AI_SI_Reload_Mode(0);
                /* AI_SI_Initial_Load_Source=A */
                mode2 &= ~AI_SI_Initial_Load_Source;
                //mode2 |= AI_SC_Reload_Mode;
-               win_out(mode2, AI_Mode_2_Register);
+               devpriv->stc_writew(dev, mode2, AI_Mode_2_Register);
 
                /* load SI */
-               timer=ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
-               win_out2(timer,AI_SI_Load_A_Registers);
-               win_out(AI_SI_Load,AI_Command_1_Register);
+               timer = ni_ns_to_timer(dev, cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
+               devpriv->stc_writel(dev, timer,AI_SI_Load_A_Registers);
+               devpriv->stc_writew(dev, AI_SI_Load,AI_Command_1_Register);
                break;
        case TRIG_EXT:
-
-/* Level trigger usually doesn't work, making it the default
- * doesn't make sense.  Disabling it. */
-/*             if( cmd->scan_begin_arg & CR_EDGE ) */
-               start_stop_select |= 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 )
                        start_stop_select |= AI_START_Polarity;
                if( cmd->scan_begin_src != cmd->convert_src ||
                        ( cmd->scan_begin_arg & ~CR_EDGE ) != ( cmd->convert_arg & ~CR_EDGE ) )
                        start_stop_select |= AI_START_Sync;
-               start_stop_select |= AI_START_Select(1+(cmd->scan_begin_arg&0xf));
-               win_out(start_stop_select, AI_START_STOP_Select_Register);
+               start_stop_select |= AI_START_Select(1 + CR_CHAN(cmd->scan_begin_arg));
+               devpriv->stc_writew(dev, start_stop_select, AI_START_STOP_Select_Register);
                break;
        }
 
@@ -1722,32 +2215,32 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
                if( cmd->convert_arg == 0 || cmd->convert_src == TRIG_NOW )
                        timer = 1;
                else
-                       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);
+                       timer = ni_ns_to_timer(dev, cmd->convert_arg, TRIG_ROUND_NEAREST);
+               devpriv->stc_writew(dev, 1,AI_SI2_Load_A_Register); /* 0,0 does not work. */
+               devpriv->stc_writew(dev, timer,AI_SI2_Load_B_Register);
 
                /* AI_SI2_Reload_Mode = alternate */
                /* AI_SI2_Initial_Load_Source = A */
                mode2 &= ~AI_SI2_Initial_Load_Source;
                mode2 |= AI_SI2_Reload_Mode;
-               win_out( mode2, AI_Mode_2_Register);
+               devpriv->stc_writew(dev,  mode2, AI_Mode_2_Register);
 
                /* AI_SI2_Load */
-               win_out(AI_SI2_Load,AI_Command_1_Register);
+               devpriv->stc_writew(dev, AI_SI2_Load,AI_Command_1_Register);
 
                mode2 |= AI_SI2_Reload_Mode; // alternate
                mode2 |= AI_SI2_Initial_Load_Source; // B
 
-               win_out(mode2,AI_Mode_2_Register);
+               devpriv->stc_writew(dev, mode2,AI_Mode_2_Register);
                break;
        case TRIG_EXT:
                mode1 |= AI_CONVERT_Source_Select(1+cmd->convert_arg);
                if( ( cmd->convert_arg & CR_INVERT ) == 0 )
                        mode1 |= AI_CONVERT_Source_Polarity;
-               win_out(mode1,AI_Mode_1_Register);
+               devpriv->stc_writew(dev, mode1,AI_Mode_1_Register);
 
                mode2 |= AI_Start_Stop_Gate_Enable | AI_SC_Gate_Enable;
-               win_out(mode2, AI_Mode_2_Register);
+               devpriv->stc_writew(dev, mode2, AI_Mode_2_Register);
 
                break;
        }
@@ -1762,7 +2255,7 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
                interrupt_a_enable|=AI_FIFO_Interrupt_Enable;
 #endif
 
-               if(cmd->flags & TRIG_WAKE_EOS){
+               if(cmd->flags & TRIG_WAKE_EOS || (devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)){
                        /* wake on end-of-scan */
                        devpriv->aimode=AIMODE_SCAN;
                }else{
@@ -1773,20 +2266,20 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
                case AIMODE_HALF_FULL:
                        /*generate FIFO interrupts and DMA requests on half-full */
 #ifdef PCIDMA
-                       win_out(AI_FIFO_Mode_HF_to_E, AI_Mode_3_Register);
+                       devpriv->stc_writew(dev, AI_FIFO_Mode_HF_to_E, AI_Mode_3_Register);
 #else
-                       win_out(AI_FIFO_Mode_HF, AI_Mode_3_Register);
+                       devpriv->stc_writew(dev, AI_FIFO_Mode_HF, AI_Mode_3_Register);
 #endif
                        break;
                case AIMODE_SAMPLE:
                        /*generate FIFO interrupts on non-empty */
-                       win_out(AI_FIFO_Mode_NE, AI_Mode_3_Register);
+                       devpriv->stc_writew(dev, AI_FIFO_Mode_NE, AI_Mode_3_Register);
                        break;
                case AIMODE_SCAN:
 #ifdef PCIDMA
-                       win_out(AI_FIFO_Mode_NE, AI_Mode_3_Register);
+                       devpriv->stc_writew(dev, AI_FIFO_Mode_NE, AI_Mode_3_Register);
 #else
-                       win_out(AI_FIFO_Mode_HF, AI_Mode_3_Register);
+                       devpriv->stc_writew(dev, AI_FIFO_Mode_HF, AI_Mode_3_Register);
 #endif
                        interrupt_a_enable |= AI_STOP_Interrupt_Enable;
                        break;
@@ -1794,7 +2287,7 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
                        break;
                }
 
-               win_out(0x3f80,Interrupt_A_Ack_Register); /* clear interrupts */
+               devpriv->stc_writew(dev, 0x3f80,Interrupt_A_Ack_Register); /* clear interrupts */
 
                ni_set_bits(dev, Interrupt_A_Enable_Register, interrupt_a_enable, 1);
 
@@ -1808,29 +2301,32 @@ static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
        }
 
        /* end configuration */
-       win_out(AI_Configuration_End,Joint_Reset_Register);
+       devpriv->stc_writew(dev, AI_Configuration_End,Joint_Reset_Register);
 
        switch(cmd->scan_begin_src){
        case TRIG_TIMER:
-               win_out(AI_SI2_Arm | AI_SI_Arm | AI_DIV_Arm | AI_SC_Arm,
+               devpriv->stc_writew(dev, AI_SI2_Arm | AI_SI_Arm | AI_DIV_Arm | AI_SC_Arm,
                        AI_Command_1_Register);
                break;
        case TRIG_EXT:
                /* XXX AI_SI_Arm? */
-               win_out(AI_SI2_Arm | AI_SI_Arm | AI_DIV_Arm | AI_SC_Arm,
+               devpriv->stc_writew(dev, AI_SI2_Arm | AI_SI_Arm | AI_DIV_Arm | AI_SC_Arm,
                        AI_Command_1_Register);
                break;
        }
 
 #ifdef PCIDMA
-       ni_ai_setup_MITE_dma(dev,cmd);
+       {
+               int retval = ni_ai_setup_MITE_dma(dev);
+               if(retval) return retval;
+       }
        //mite_dump_regs(devpriv->mite);
 #endif
 
        switch(cmd->start_src){
        case TRIG_NOW:
                /* AI_START1_Pulse */
-               win_out( AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register );
+               devpriv->stc_writew(dev,  AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register );
                s->async->inttrig=NULL;
                break;
        case TRIG_EXT:
@@ -1851,7 +2347,7 @@ static int ni_ai_inttrig(comedi_device *dev,comedi_subdevice *s,
 {
        if(trignum!=0)return -EINVAL;
 
-       win_out( AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register );
+       devpriv->stc_writew(dev,  AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register );
        s->async->inttrig=NULL;
 
        return 1;
@@ -1869,21 +2365,43 @@ static int ni_ai_insn_config(comedi_device *dev,comedi_subdevice *s,
        case INSN_CONFIG_ANALOG_TRIG:
                return ni_ai_config_analog_trig(dev,s,insn,data);
        case INSN_CONFIG_ALT_SOURCE:
+               if(boardtype.reg_type & ni_reg_m_series_mask)
+               {
+                       if(data[1] & ~(MSeries_AI_Bypass_Cal_Sel_Pos_Mask |
+                               MSeries_AI_Bypass_Cal_Sel_Neg_Mask | MSeries_AI_Bypass_Mode_Mux_Mask |
+                               MSeries_AO_Bypass_AO_Cal_Sel_Mask))
+                       {
+                               return -EINVAL;
+                       }
+                       devpriv->ai_calib_source = data[1];
+               } else if(boardtype.reg_type == ni_reg_6143)
                {
-               unsigned int calib_source;
-               unsigned int calib_source_adjust;
+                       unsigned int calib_source;
 
-               calib_source = data[1] & 0xf;
-               calib_source_adjust = ( data[1] >> 4 ) & 0xff;
+                       calib_source = data[1] & 0xf;
 
-               if(calib_source >= 8)
-                       return -EINVAL;
-               devpriv->ai_calib_source = calib_source;
-               if(boardtype.reg_type == ni_reg_611x){
-                       ni_writeb( calib_source_adjust, Cal_Gain_Select_611x );
+
+                       if(calib_source > 0xF)
+                               return -EINVAL;
+
+                       devpriv->ai_calib_source = calib_source;
+                       ni_writew(calib_source, Calibration_Channel_6143);
+               }else
+               {
+                       unsigned int calib_source;
+                       unsigned int calib_source_adjust;
+
+                       calib_source = data[1] & 0xf;
+                       calib_source_adjust = ( data[1] >> 4 ) & 0xff;
+
+                       if(calib_source >= 8)
+                               return -EINVAL;
+                       devpriv->ai_calib_source = calib_source;
+                       if(boardtype.reg_type == ni_reg_611x){
+                               ni_writeb( calib_source_adjust, Cal_Gain_Select_611x );
+                       }
                }
                return 2;
-               }
        default:
                break;
        }
@@ -1902,9 +2420,8 @@ static int ni_ai_config_analog_trig(comedi_device *dev,comedi_subdevice *s,
         * data[3] is set level
         * data[4] is reset level */
        if(!boardtype.has_analog_trig)return -EINVAL;
-       if(insn->n!=5)return -EINVAL;
        if((data[1]&0xffff0000) != COMEDI_EV_SCAN_BEGIN){
-               data[1]&=~(COMEDI_EV_SCAN_BEGIN&0xffff);
+               data[1]&= (COMEDI_EV_SCAN_BEGIN | 0xffff);
                err++;
        }
        if(data[2]>=boardtype.n_adchan){
@@ -2010,8 +2527,8 @@ static void ni_ao_munge(comedi_device *dev, comedi_subdevice *s,
        }
 }
 
-static int ni_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
-       unsigned int chanspec[], unsigned int n_chans)
+static int ni_m_series_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
+       unsigned int chanspec[], unsigned int n_chans, int timed)
 {
        unsigned int range;
        unsigned int chan;
@@ -2019,10 +2536,73 @@ static int ni_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
        int i;
        int invert = 0;
 
-       for(i=0;i<n_chans;i++){
+       for(i = 0; i < boardtype.n_aochan; ++i)
+       {
+               ni_writeb(0xf, M_Offset_AO_Waveform_Order(i));
+       }
+       for(i=0;i<n_chans;i++)
+       {
+               comedi_krange *krange;
                chan = CR_CHAN(chanspec[i]);
                range = CR_RANGE(chanspec[i]);
+               krange = s->range_table->range + range;
+               invert = 0;
+               conf = 0;
+               switch(krange->max - krange->min)
+               {
+               case 20000000:
+                       conf |= MSeries_AO_DAC_Reference_10V_Internal_Bits;
+                       ni_writeb(0, M_Offset_AO_Reference_Attenuation(chan));
+                       break;
+               case 10000000:
+                       conf |= MSeries_AO_DAC_Reference_5V_Internal_Bits;
+                       ni_writeb(0, M_Offset_AO_Reference_Attenuation(chan));
+                       break;
+               case 4000000:
+                       conf |= MSeries_AO_DAC_Reference_10V_Internal_Bits;
+                       ni_writeb(MSeries_Attenuate_x5_Bit, M_Offset_AO_Reference_Attenuation(chan));
+                       break;
+               case 2000000:
+                       conf |= MSeries_AO_DAC_Reference_5V_Internal_Bits;
+                       ni_writeb(MSeries_Attenuate_x5_Bit, M_Offset_AO_Reference_Attenuation(chan));
+                       break;
+               default:
+                       rt_printk("%s: bug! unhandled ao reference voltage\n", __FUNCTION__);
+                       break;
+               }
+               switch(krange->max + krange->min)
+               {
+               case 0:
+                       conf |= MSeries_AO_DAC_Offset_0V_Bits;
+                       break;
+               case 10000000:
+                       conf |= MSeries_AO_DAC_Offset_5V_Bits;
+                       break;
+               default:
+                       rt_printk("%s: bug! unhandled ao offset voltage\n", __FUNCTION__);
+                       break;
+               }
+               if(timed) conf |= MSeries_AO_Update_Timed_Bit;
+               ni_writeb(conf, M_Offset_AO_Config_Bank(chan));
+               devpriv->ao_conf[chan] = conf;
+               ni_writeb(i, M_Offset_AO_Waveform_Order(chan));
+       }
+       return invert;
+}
+
+static int ni_old_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 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.ao_unipolar){
@@ -2047,13 +2627,20 @@ static int ni_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
                /* 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;
-
                ni_writew(conf,AO_Configuration);
+               devpriv->ao_conf[chan] = conf;
        }
        return invert;
 }
 
+static int ni_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
+       unsigned int chanspec[], unsigned int n_chans, int timed)
+{
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+               return ni_m_series_ao_config_chanlist(dev, s, chanspec, n_chans, timed);
+       else
+               return ni_old_ao_config_chanlist(dev, s, chanspec, n_chans);
+}
 static int ni_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data)
 {
@@ -2068,11 +2655,16 @@ static int ni_ao_insn_write(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);
+       invert = ni_ao_config_chanlist(dev,s,&insn->chanspec, 1, 0);
 
        devpriv->ao[chan] = data[0];
 
-       ni_writew(data[0] ^ invert,(chan)? DAC1_Direct_Data : DAC0_Direct_Data);
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+       {
+               ni_writew(data[0], M_Offset_DAC_Direct_Data(chan));
+       }
+       else
+               ni_writew(data[0] ^ invert,(chan)? DAC1_Direct_Data : DAC0_Direct_Data);
 
        return 1;
 }
@@ -2086,7 +2678,7 @@ static int ni_ao_insn_write_671x(comedi_device *dev,comedi_subdevice *s,
        ao_win_out(1 << chan, AO_Immediate_671x);
        invert = 1 << (boardtype.aobits - 1);
 
-       ni_ao_config_chanlist(dev,s,&insn->chanspec,1);
+       ni_ao_config_chanlist(dev,s,&insn->chanspec, 1, 0);
 
        devpriv->ao[chan] = data[0];
        ao_win_out(data[0] ^ invert, DACx_Direct_Data_671x(chan));
@@ -2098,37 +2690,53 @@ static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s,
        unsigned int trignum)
 {
        int ret;
-       int bits;
-
-       if(trignum!=0)return -EINVAL;
-
-       win_out(devpriv->ao_mode3|AO_Not_An_UPDATE,AO_Mode_3_Register);
-       win_out(devpriv->ao_mode3,AO_Mode_3_Register);
-
-       /* wait for DACs to be loaded */
-       comedi_udelay(100);
+       int interrupt_b_bits;
+       int i;
+       static const int timeout = 1000;
 
-       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);
+       if(trignum!=0) return -EINVAL;
 
-       bits = AO_Error_Interrupt_Enable;
+       ni_set_bits(dev, Interrupt_B_Enable_Register, AO_FIFO_Interrupt_Enable | AO_Error_Interrupt_Enable, 0);
+       interrupt_b_bits = AO_Error_Interrupt_Enable;
 #ifdef PCIDMA
-       win_out(0, DAC_FIFO_Clear);
-       ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
-       ni_ao_setup_MITE_dma(dev, &s->async->cmd);
+       devpriv->stc_writew(dev, 1, DAC_FIFO_Clear);
+       if(boardtype.reg_type & ni_reg_6xxx_mask)
+               ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
+       ret = ni_ao_setup_MITE_dma(dev);
+       if(ret) return ret;
        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;
+       interrupt_b_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);
+       devpriv->stc_writew(dev, devpriv->ao_mode3|AO_Not_An_UPDATE,AO_Mode_3_Register);
+       devpriv->stc_writew(dev, devpriv->ao_mode3,AO_Mode_3_Register);
+       /* wait for DACs to be loaded */
+       for(i = 0; i < timeout; i++)
+       {
+               comedi_udelay(1);
+               if((devpriv->stc_readw(dev, Joint_Status_2_Register) & AO_TMRDACWRs_In_Progress_St) == 0)
+                       break;
+       }
+       if(i == timeout)
+       {
+               comedi_error(dev, "timed out waiting for AO_TMRDACWRs_In_Progress_St to clear");
+               return -EIO;
+       }
+       // stc manual says we are need to clear error interrupt after AO_TMRDACWRs_In_Progress_St clears
+       devpriv->stc_writew(dev, AO_Error_Interrupt_Ack, Interrupt_B_Ack_Register);
+
+       ni_set_bits(dev, Interrupt_B_Enable_Register, interrupt_b_bits, 1);
+
+       devpriv->stc_writew(dev, devpriv->ao_cmd1|AO_UI_Arm|AO_UC_Arm|AO_BC_Arm|AO_DAC1_Update_Mode|AO_DAC0_Update_Mode,
+               AO_Command_1_Register);
+
+       devpriv->stc_writew(dev, devpriv->ao_cmd2|AO_START1_Pulse,AO_Command_2_Register);
 
        s->async->inttrig=NULL;
 
@@ -2137,16 +2745,21 @@ static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s,
 
 static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s)
 {
-       comedi_cmd *cmd = &s->async->cmd;
+       const comedi_cmd *cmd = &s->async->cmd;
        int trigvar;
        int bits;
        int i;
 
-       trigvar = ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
+       if(dev->irq == 0)
+       {
+               comedi_error(dev, "cannot run command without an irq");
+               return -EIO;
+       }
+       trigvar = ni_ns_to_timer(dev, cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
 
-       win_out(AO_Configuration_Start,Joint_Reset_Register);
+       devpriv->stc_writew(dev, AO_Configuration_Start,Joint_Reset_Register);
 
-       win_out(AO_Disarm,AO_Command_1_Register);
+       devpriv->stc_writew(dev, AO_Disarm,AO_Command_1_Register);
 
        if(boardtype.reg_type & ni_reg_6xxx_mask)
        {
@@ -2164,7 +2777,7 @@ static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s)
                ao_win_out(bits, AO_Timed_611x);
        }
 
-       ni_ao_config_chanlist(dev,s,cmd->chanlist,cmd->chanlist_len);
+       ni_ao_config_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len, 1);
 
        if(cmd->stop_src==TRIG_NONE){
                devpriv->ao_mode1|=AO_Continuous;
@@ -2173,92 +2786,107 @@ static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s)
                devpriv->ao_mode1&=~AO_Continuous;
                devpriv->ao_mode1|=AO_Trigger_Once;
        }
-       win_out(devpriv->ao_mode1,AO_Mode_1_Register);
+       devpriv->stc_writew(dev, devpriv->ao_mode1,AO_Mode_1_Register);
        devpriv->ao_trigger_select&=~(AO_START1_Polarity|AO_START1_Select(-1));
        devpriv->ao_trigger_select|=AO_START1_Edge|AO_START1_Sync;
-       win_out(devpriv->ao_trigger_select,AO_Trigger_Select_Register);
+       devpriv->stc_writew(dev, devpriv->ao_trigger_select,AO_Trigger_Select_Register);
        devpriv->ao_mode3&=~AO_Trigger_Length;
-       win_out(devpriv->ao_mode3,AO_Mode_3_Register);
+       devpriv->stc_writew(dev, devpriv->ao_mode3,AO_Mode_3_Register);
 
-       win_out(devpriv->ao_mode1,AO_Mode_1_Register);
+       devpriv->stc_writew(dev, devpriv->ao_mode1,AO_Mode_1_Register);
        devpriv->ao_mode2&=~AO_BC_Initial_Load_Source;
-       win_out(devpriv->ao_mode2,AO_Mode_2_Register);
+       devpriv->stc_writew(dev, devpriv->ao_mode2,AO_Mode_2_Register);
        if(cmd->stop_src==TRIG_NONE){
-               win_out2(0xffffff,AO_BC_Load_A_Register);
+               devpriv->stc_writel(dev, 0xffffff,AO_BC_Load_A_Register);
        }else{
-               win_out2(0,AO_BC_Load_A_Register);
+               devpriv->stc_writel(dev, 0,AO_BC_Load_A_Register);
        }
-       win_out(AO_BC_Load,AO_Command_1_Register);
+       devpriv->stc_writew(dev, AO_BC_Load,AO_Command_1_Register);
        devpriv->ao_mode2&=~AO_UC_Initial_Load_Source;
-       win_out(devpriv->ao_mode2,AO_Mode_2_Register);
+       devpriv->stc_writew(dev, devpriv->ao_mode2,AO_Mode_2_Register);
        switch(cmd->stop_src){
        case TRIG_COUNT:
-               win_out2(cmd->stop_arg,AO_UC_Load_A_Register);
-               win_out(AO_UC_Load,AO_Command_1_Register);
-               win_out2(cmd->stop_arg - 1,AO_UC_Load_A_Register);
+               devpriv->stc_writel(dev, cmd->stop_arg,AO_UC_Load_A_Register);
+               devpriv->stc_writew(dev, AO_UC_Load,AO_Command_1_Register);
+               devpriv->stc_writel(dev, cmd->stop_arg - 1,AO_UC_Load_A_Register);
                break;
        case TRIG_NONE:
-               win_out2(0xffffff,AO_UC_Load_A_Register);
-               win_out(AO_UC_Load,AO_Command_1_Register);
-               win_out2(0xffffff,AO_UC_Load_A_Register);
+               devpriv->stc_writel(dev, 0xffffff,AO_UC_Load_A_Register);
+               devpriv->stc_writew(dev, AO_UC_Load,AO_Command_1_Register);
+               devpriv->stc_writel(dev, 0xffffff,AO_UC_Load_A_Register);
                break;
        default:
-               win_out2(0,AO_UC_Load_A_Register);
-               win_out(AO_UC_Load,AO_Command_1_Register);
-               win_out2(cmd->stop_arg,AO_UC_Load_A_Register);
+               devpriv->stc_writel(dev, 0,AO_UC_Load_A_Register);
+               devpriv->stc_writew(dev, AO_UC_Load,AO_Command_1_Register);
+               devpriv->stc_writel(dev, cmd->stop_arg,AO_UC_Load_A_Register);
        }
 
        devpriv->ao_cmd2&=~AO_BC_Gate_Enable;
-       win_out(devpriv->ao_cmd2,AO_Command_2_Register);
+       devpriv->stc_writew(dev, devpriv->ao_cmd2,AO_Command_2_Register);
        devpriv->ao_mode1&=~(AO_UI_Source_Select(0x1f)|AO_UI_Source_Polarity);
-       win_out(devpriv->ao_mode1,AO_Mode_1_Register);
+       devpriv->stc_writew(dev, devpriv->ao_mode1,AO_Mode_1_Register);
        devpriv->ao_mode2&=~(AO_UI_Reload_Mode(3)|AO_UI_Initial_Load_Source);
-       win_out(devpriv->ao_mode2,AO_Mode_2_Register);
-       win_out2(1,AO_UI_Load_A_Register);
-       win_out(AO_UI_Load,AO_Command_1_Register);
-       win_out2(trigvar,AO_UI_Load_A_Register);
+       devpriv->stc_writew(dev, devpriv->ao_mode2,AO_Mode_2_Register);
+       devpriv->stc_writel(dev, 1,AO_UI_Load_A_Register);
+       devpriv->stc_writew(dev, AO_UI_Load,AO_Command_1_Register);
+       devpriv->stc_writel(dev, trigvar,AO_UI_Load_A_Register);
 
-       if(boardtype.reg_type == ni_reg_normal){
+       if((boardtype.reg_type & ni_reg_6xxx_mask) == 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),
+                       devpriv->stc_writew(dev, AO_Number_Of_Channels(cmd->scan_end_arg-1)|
+                               AO_UPDATE_Output_Select(AO_Update_Output_High_Z),
                                AO_Output_Control_Register);
                }else{
+                       unsigned bits;
                        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);
+                       bits = AO_UPDATE_Output_Select(AO_Update_Output_High_Z);
+                       if(boardtype.reg_type & ni_reg_m_series_mask)
+                       {
+                               bits |= AO_Number_Of_Channels(0);
+                       }else
+                       {
+                               bits |= AO_Number_Of_Channels(CR_CHAN(cmd->chanlist[0]));
+                       }
+                       devpriv->stc_writew(dev, bits, AO_Output_Control_Register);
                }
-               win_out(devpriv->ao_mode1,AO_Mode_1_Register);
+               devpriv->stc_writew(dev, devpriv->ao_mode1,AO_Mode_1_Register);
        }
 
-       win_out(AO_DAC0_Update_Mode|AO_DAC1_Update_Mode,AO_Command_1_Register);
+       devpriv->stc_writew(dev, 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->stc_writew(dev, devpriv->ao_mode3,AO_Mode_3_Register);
 
-       devpriv->ao_mode2 &= AO_FIFO_Mode_Mask;
+       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);
+       devpriv->stc_writew(dev, 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);
+       else
+               bits |= AO_DMA_PIO_Control;
+#if 0
+       /* F Hess: windows driver does not set AO_Number_Of_DAC_Packages bit for 6281,
+       verified with bus analyzer. */
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+               bits |= AO_Number_Of_DAC_Packages;
+#endif
+       devpriv->stc_writew(dev, bits, AO_Personal_Register);
        // enable sending of ao dma requests
-       win_out(AO_AOFREQ_Enable, AO_Start_Select_Register);
+       devpriv->stc_writew(dev, AO_AOFREQ_Enable, AO_Start_Select_Register);
 
-       win_out(AO_Configuration_End,Joint_Reset_Register);
+       devpriv->stc_writew(dev, AO_Configuration_End,Joint_Reset_Register);
 
        if(cmd->stop_src==TRIG_COUNT) {
-               win_out(AO_BC_TC_Interrupt_Ack,Interrupt_B_Ack_Register);
+               devpriv->stc_writew(dev, AO_BC_TC_Interrupt_Ack,Interrupt_B_Ack_Register);
                ni_set_bits(dev, Interrupt_B_Enable_Register,
                        AO_BC_TC_Interrupt_Enable, 1);
        }
@@ -2310,15 +2938,12 @@ static int ni_ao_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
                cmd->start_arg=0;
                err++;
        }
-#if 0
-       /* XXX need ao_speed */
-       if(cmd->scan_begin_arg<boardtype.ao_speed){
-               cmd->scan_begin_arg=boardtype.ao_speed;
+       if(cmd->scan_begin_arg < boardtype.ao_speed){
+               cmd->scan_begin_arg = boardtype.ao_speed;
                err++;
        }
-#endif
-       if(cmd->scan_begin_arg>TIMER_BASE*0xffffff){ /* XXX check */
-               cmd->scan_begin_arg=TIMER_BASE*0xffffff;
+       if(cmd->scan_begin_arg > devpriv->clock_ns * 0xffffff){ /* XXX check */
+               cmd->scan_begin_arg = devpriv->clock_ns * 0xffffff;
                err++;
        }
        if(cmd->convert_arg!=0){
@@ -2347,18 +2972,13 @@ static int ni_ao_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
        /* step 4: fix up any arguments */
 
        tmp = cmd->scan_begin_arg;
-       ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
+       cmd->scan_begin_arg = ni_timer_to_ns(dev, ni_ns_to_timer(dev, cmd->scan_begin_arg, cmd->flags&TRIG_ROUND_MASK));
        if(tmp!=cmd->scan_begin_arg)err++;
 
        if(err)return 4;
 
        /* step 5: fix up chanlist */
 
-       if(cmd->chanlist_len != cmd->scan_end_arg){
-               cmd->chanlist_len = cmd->scan_end_arg;
-               err++;
-       }
-
        if(err)return 5;
 
        return 0;
@@ -2373,32 +2993,37 @@ 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
+       ni_release_ao_mite_channel(dev);
 
-       win_out(AO_Configuration_Start,Joint_Reset_Register);
-       win_out(AO_Disarm,AO_Command_1_Register);
+       devpriv->stc_writew(dev, AO_Configuration_Start,Joint_Reset_Register);
+       devpriv->stc_writew(dev, AO_Disarm,AO_Command_1_Register);
        ni_set_bits(dev,Interrupt_B_Enable_Register,~0,0);
-       win_out(0x0010,AO_Personal_Register);
-       win_out(0x3f98,Interrupt_B_Ack_Register);
-       win_out(AO_BC_Source_Select | AO_UPDATE_Pulse_Width |
+       devpriv->stc_writew(dev, AO_BC_Source_Select, AO_Personal_Register);
+       devpriv->stc_writew(dev, 0x3f98,Interrupt_B_Ack_Register);
+       devpriv->stc_writew(dev, 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->stc_writew(dev, 0,AO_Output_Control_Register);
+       devpriv->stc_writew(dev, 0,AO_Start_Select_Register);
        devpriv->ao_cmd1=0;
-       win_out(devpriv->ao_cmd1,AO_Command_1_Register);
+       devpriv->stc_writew(dev, devpriv->ao_cmd1,AO_Command_1_Register);
        devpriv->ao_cmd2=0;
+       devpriv->stc_writew(dev, devpriv->ao_cmd2, AO_Command_2_Register);
        devpriv->ao_mode1=0;
+       devpriv->stc_writew(dev, devpriv->ao_mode1, AO_Mode_1_Register);
        devpriv->ao_mode2=0;
-       devpriv->ao_mode3=0;
-       devpriv->ao_trigger_select=0;
+       devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register);
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+               devpriv->ao_mode3 = AO_Last_Gate_Disable;
+       else
+               devpriv->ao_mode3 = 0;
+       devpriv->stc_writew(dev, devpriv->ao_mode3, AO_Mode_3_Register);
+       devpriv->ao_trigger_select = 0;
+       devpriv->stc_writew(dev, devpriv->ao_trigger_select,AO_Trigger_Select_Register);
        if(boardtype.reg_type & ni_reg_6xxx_mask){
                ao_win_out(0x3, AO_Immediate_671x);
                ao_win_out(CLEAR_WG, AO_Misc_611x);
        }
+       devpriv->stc_writew(dev, AO_Configuration_End, Joint_Reset_Register);
 
        return 0;
 }
@@ -2407,24 +3032,27 @@ static int ni_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data)
 {
 #ifdef DEBUG_DIO
-       printk("ni_dio_insn_config() chan=%d io=%d\n",
+       rt_printk("ni_dio_insn_config() chan=%d io=%d\n",
                CR_CHAN(insn->chanspec),data[0]);
 #endif
-       if(insn->n!=1)return -EINVAL;
        switch(data[0]){
-       case COMEDI_OUTPUT:
+       case INSN_CONFIG_DIO_OUTPUT:
                s->io_bits |= 1<<CR_CHAN(insn->chanspec);
                break;
-       case COMEDI_INPUT:
+       case INSN_CONFIG_DIO_INPUT:
                s->io_bits &= ~(1<<CR_CHAN(insn->chanspec));
                break;
+       case INSN_CONFIG_DIO_QUERY:
+               data[1] = (s->io_bits & (1<<CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : COMEDI_INPUT;
+               return insn->n;
+               break;
        default:
                return -EINVAL;
        }
 
        devpriv->dio_control &= ~DIO_Pins_Dir_Mask;
        devpriv->dio_control |= DIO_Pins_Dir(s->io_bits);
-       win_out(devpriv->dio_control,DIO_Control_Register);
+       devpriv->stc_writew(dev, devpriv->dio_control,DIO_Control_Register);
 
        return 1;
 }
@@ -2433,7 +3061,7 @@ static int ni_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data)
 {
 #ifdef DEBUG_DIO
-       printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n",data[0],data[1]);
+       rt_printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n",data[0],data[1]);
 #endif
        if(insn->n!=2)return -EINVAL;
        if(data[0]){
@@ -2446,9 +3074,54 @@ static int ni_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,
                s->state |= (data[0]&data[1]);
                devpriv->dio_output &= ~DIO_Parallel_Data_Mask;
                devpriv->dio_output |= DIO_Parallel_Data_Out(s->state);
-               win_out(devpriv->dio_output,DIO_Output_Register);
+               devpriv->stc_writew(dev, devpriv->dio_output,DIO_Output_Register);
+       }
+       data[1] = devpriv->stc_readw(dev, DIO_Parallel_Input_Register);
+
+       return 2;
+}
+
+static int ni_m_series_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+#ifdef DEBUG_DIO
+       rt_printk("ni_m_series_dio_insn_config() chan=%d io=%d\n",
+               CR_CHAN(insn->chanspec), data[0]);
+#endif
+       switch(data[0])
+       {
+       case INSN_CONFIG_DIO_OUTPUT:
+               s->io_bits |= 1 << CR_CHAN(insn->chanspec);
+               break;
+       case INSN_CONFIG_DIO_INPUT:
+               s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
+               break;
+       case INSN_CONFIG_DIO_QUERY:
+               data[1] = (s->io_bits & (1<<CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : COMEDI_INPUT;
+               return insn->n;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ni_writel(s->io_bits, M_Offset_DIO_Direction);
+
+       return 1;
+}
+
+static int ni_m_series_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+#ifdef DEBUG_DIO
+       rt_printk("ni_m_series_dio_insn_bits() mask=0x%x bits=0x%x\n",data[0],data[1]);
+#endif
+       if(insn->n!=2)return -EINVAL;
+       if(data[0]){
+               s->state &= ~data[0];
+               s->state |= (data[0] & data[1]);
+               ni_writel(s->state, M_Offset_Static_Digital_Output);
        }
-       data[1] = win_in(DIO_Parallel_Input_Register);
+       data[1] = ni_readl(M_Offset_Static_Digital_Input);
 
        return 2;
 }
@@ -2465,7 +3138,7 @@ static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
        case INSN_CONFIG_SERIAL_CLOCK:
 
 #ifdef DEBUG_DIO
-               printk("SPI serial clock Config cd\n", data[1]);
+               rt_printk("SPI serial clock Config cd\n", data[1]);
 #endif
                devpriv->serial_hw_mode = 1;
                devpriv->dio_control |= DIO_HW_Serial_Enable;
@@ -2512,8 +3185,8 @@ static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
                        devpriv->serial_interval_ns = data[1];
                }
 
-               win_out(devpriv->dio_control,DIO_Control_Register);
-               win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
+               devpriv->stc_writew(dev, devpriv->dio_control,DIO_Control_Register);
+               devpriv->stc_writew(dev, devpriv->clock_and_fout,Clock_and_FOUT_Register);
                return 1;
 
        break;
@@ -2531,7 +3204,7 @@ static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
                } else if(devpriv->serial_interval_ns > 0) {
                        err = ni_serial_sw_readwrite8(dev,s,byte_out,&byte_in);
                } else {
-                       printk("ni_serial_insn_config: serial disabled!\n");
+                       rt_printk("ni_serial_insn_config: serial disabled!\n");
                        return -EINVAL;
                }
                if(err < 0) return err;
@@ -2553,29 +3226,29 @@ static int ni_serial_hw_readwrite8(comedi_device *dev,comedi_subdevice *s,
        int err = 0, count = 20;
 
 #ifdef DEBUG_DIO
-       printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out);
+       rt_printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out);
 #endif
 
        devpriv->dio_output &= ~DIO_Serial_Data_Mask;
        devpriv->dio_output |= DIO_Serial_Data_Out(data_out);
-       win_out(devpriv->dio_output,DIO_Output_Register);
+       devpriv->stc_writew(dev, devpriv->dio_output,DIO_Output_Register);
 
-       status1 = win_in(Joint_Status_1_Register);
+       status1 = devpriv->stc_readw(dev, Joint_Status_1_Register);
        if(status1 & DIO_Serial_IO_In_Progress_St) {
                err = -EBUSY;
                goto Error;
        }
 
        devpriv->dio_control |= DIO_HW_Serial_Start;
-       win_out(devpriv->dio_control,DIO_Control_Register);
+       devpriv->stc_writew(dev, devpriv->dio_control,DIO_Control_Register);
        devpriv->dio_control &= ~DIO_HW_Serial_Start;
 
        /* Wait until STC says we're done, but don't loop infinitely. */
-       while((status1 = win_in(Joint_Status_1_Register)) & DIO_Serial_IO_In_Progress_St) {
+       while((status1 = devpriv->stc_readw(dev, Joint_Status_1_Register)) & DIO_Serial_IO_In_Progress_St) {
                /* Delay one bit per loop */
                comedi_udelay((devpriv->serial_interval_ns + 999) / 1000);
                if(--count < 0) {
-                       printk("ni_serial_hw_readwrite8: SPI serial I/O didn't finish in time!\n");
+                       rt_printk("ni_serial_hw_readwrite8: SPI serial I/O didn't finish in time!\n");
                        err = -ETIME;
                        goto Error;
                }
@@ -2586,14 +3259,14 @@ static int ni_serial_hw_readwrite8(comedi_device *dev,comedi_subdevice *s,
        comedi_udelay((devpriv->serial_interval_ns + 999) / 1000);
 
        if(data_in != NULL) {
-               *data_in = win_in(DIO_Serial_Input_Register);
+               *data_in = devpriv->stc_readw(dev, DIO_Serial_Input_Register);
 #ifdef DEBUG_DIO
-               printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in);
+               rt_printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in);
 #endif
        }
 
  Error:
-       win_out(devpriv->dio_control,DIO_Control_Register);
+       devpriv->stc_writew(dev, devpriv->dio_control,DIO_Control_Register);
 
        return err;
 }
@@ -2605,7 +3278,7 @@ static int ni_serial_sw_readwrite8(comedi_device *dev,comedi_subdevice *s,
        unsigned char mask, input = 0;
 
 #ifdef DEBUG_DIO
-       printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out);
+       rt_printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out);
 #endif
 
        /* Wait for one bit before transfer */
@@ -2619,28 +3292,28 @@ static int ni_serial_sw_readwrite8(comedi_device *dev,comedi_subdevice *s,
                if(data_out & mask) {
                        devpriv->dio_output |= DIO_SDOUT;
                }
-               win_out(devpriv->dio_output,DIO_Output_Register);
+               devpriv->stc_writew(dev, devpriv->dio_output,DIO_Output_Register);
 
                /* Assert SDCLK (active low, inverted), wait for half of
                   the delay, deassert SDCLK, and wait for the other half. */
                devpriv->dio_control |= DIO_Software_Serial_Control;
-               win_out(devpriv->dio_control,DIO_Control_Register);
+               devpriv->stc_writew(dev, devpriv->dio_control,DIO_Control_Register);
 
                comedi_udelay((devpriv->serial_interval_ns + 999) / 2000);
 
                devpriv->dio_control &= ~DIO_Software_Serial_Control;
-               win_out(devpriv->dio_control,DIO_Control_Register);
+               devpriv->stc_writew(dev, devpriv->dio_control,DIO_Control_Register);
 
                comedi_udelay((devpriv->serial_interval_ns + 999) / 2000);
 
                /* Input current bit */
-               if(win_in(DIO_Parallel_Input_Register) & DIO_SDIN) {
-/*                     printk("DIO_P_I_R: 0x%x\n", win_in(DIO_Parallel_Input_Register)); */
+               if(devpriv->stc_readw(dev, DIO_Parallel_Input_Register) & DIO_SDIN) {
+/*                     rt_printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */
                        input |= mask;
                }
        }
 #ifdef DEBUG_DIO
-       printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input);
+       rt_printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input);
 #endif
        if(data_in) *data_in = input;
 
@@ -2661,6 +3334,149 @@ static void init_ao_67xx(comedi_device *dev, comedi_subdevice *s)
                ni_ao_win_outw(dev, AO_Channel(i) | 0x0, AO_Configuration_2_67xx);
 }
 
+static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg)
+{
+       unsigned stc_register;
+       switch(reg)
+       {
+       case NITIO_G0_Autoincrement_Reg:
+               stc_register = G_Autoincrement_Register(0);
+               break;
+       case NITIO_G1_Autoincrement_Reg:
+               stc_register = G_Autoincrement_Register(1);
+               break;
+       case NITIO_G0_Command_Reg:
+               stc_register = G_Command_Register(0);
+               break;
+       case NITIO_G1_Command_Reg:
+               stc_register = G_Command_Register(1);
+               break;
+       case NITIO_G0_HW_Save_Reg:
+               stc_register = G_HW_Save_Register(0);
+               break;
+       case NITIO_G1_HW_Save_Reg:
+               stc_register = G_HW_Save_Register(1);
+               break;
+       case NITIO_G0_SW_Save_Reg:
+               stc_register = G_Save_Register(0);
+               break;
+       case NITIO_G1_SW_Save_Reg:
+               stc_register = G_Save_Register(1);
+               break;
+       case NITIO_G0_Mode_Reg:
+               stc_register = G_Mode_Register(0);
+               break;
+       case NITIO_G1_Mode_Reg:
+               stc_register = G_Mode_Register(1);
+               break;
+       case NITIO_G0_LoadA_Reg:
+               stc_register = G_Load_A_Register(0);
+               break;
+       case NITIO_G1_LoadA_Reg:
+               stc_register = G_Load_A_Register(1);
+               break;
+       case NITIO_G0_LoadB_Reg:
+               stc_register = G_Load_B_Register(0);
+               break;
+       case NITIO_G1_LoadB_Reg:
+               stc_register = G_Load_B_Register(1);
+               break;
+       case NITIO_G0_Input_Select_Reg:
+               stc_register = G_Input_Select_Register(0);
+               break;
+       case NITIO_G1_Input_Select_Reg:
+               stc_register = G_Input_Select_Register(1);
+               break;
+       case NITIO_G01_Status_Reg:
+               stc_register = G_Status_Register;
+               break;
+       case NITIO_G01_Joint_Reset_Reg:
+               stc_register = Joint_Reset_Register;
+               break;
+       case NITIO_G01_Joint_Status1_Reg:
+               stc_register = Joint_Status_1_Register;
+               break;
+       case NITIO_G01_Joint_Status2_Reg:
+               stc_register = Joint_Status_2_Register;
+               break;
+       default:
+               rt_printk("%s: unhandled register 0x%x in switch.\n", __FUNCTION__, reg);
+               BUG();
+               return 0;
+               break;
+       }
+       return stc_register;
+}
+
+static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg)
+{
+       comedi_device *dev = counter->dev;
+       unsigned stc_register;
+       /* bits in the join reset register which are relevant to counters */
+       static const unsigned gpct_joint_reset_mask = G0_Reset | G1_Reset;
+       switch(reg)
+       {
+       /* m-series-only registers */
+       case NITIO_G0_Counting_Mode_Reg:
+               ni_writew(bits, M_Offset_G0_Counting_Mode);
+               break;
+       case NITIO_G1_Counting_Mode_Reg:
+               ni_writew(bits, M_Offset_G1_Counting_Mode);
+               break;
+       case NITIO_G0_Second_Gate_Reg:
+               ni_writew(bits, M_Offset_G0_Second_Gate);
+               break;
+       case NITIO_G1_Second_Gate_Reg:
+               ni_writew(bits, M_Offset_G1_Second_Gate);
+               break;
+       case NITIO_G0_ABZ_Reg:
+               ni_writew(bits, M_Offset_G0_MSeries_ABZ);
+               break;
+       case NITIO_G1_ABZ_Reg:
+               ni_writew(bits, M_Offset_G1_MSeries_ABZ);
+               break;
+
+       /* 32 bit registers */
+       case NITIO_G0_LoadA_Reg:
+       case NITIO_G1_LoadA_Reg:
+       case NITIO_G0_LoadB_Reg:
+       case NITIO_G1_LoadB_Reg:
+               stc_register = ni_gpct_to_stc_register(reg);
+               devpriv->stc_writel(dev, bits, stc_register);
+               break;
+       /* 16 bit registers */
+       case NITIO_G01_Joint_Reset_Reg:
+               BUG_ON(bits & ~gpct_joint_reset_mask);
+               /* fall-through */
+       default:
+               stc_register = ni_gpct_to_stc_register(reg);
+               devpriv->stc_writew(dev, bits, stc_register);
+       }
+}
+
+static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg)
+{
+       comedi_device *dev = counter->dev;
+       unsigned stc_register;
+       switch(reg)
+       {
+       /* 32 bit registers */
+       case NITIO_G0_HW_Save_Reg:
+       case NITIO_G1_HW_Save_Reg:
+       case NITIO_G0_SW_Save_Reg:
+       case NITIO_G1_SW_Save_Reg:
+               stc_register = ni_gpct_to_stc_register(reg);
+               return devpriv->stc_readl(dev, stc_register);
+               break;
+       /* 16 bit registers */
+       default:
+               stc_register = ni_gpct_to_stc_register(reg);
+               return devpriv->stc_readw(dev, stc_register);
+               break;
+       }
+       return 0;
+}
+
 static int ni_alloc_private(comedi_device *dev)
 {
        int ret;
@@ -2669,6 +3485,8 @@ static int ni_alloc_private(comedi_device *dev)
        if(ret < 0) return ret;
 
        spin_lock_init(&devpriv->window_lock);
+       spin_lock_init(&devpriv->soft_reg_copy_lock);
+       spin_lock_init(&devpriv->mite_channel_lock);
 
        return 0;
 };
@@ -2676,9 +3494,15 @@ static int ni_alloc_private(comedi_device *dev)
 static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
 {
        comedi_subdevice *s;
-       int bits;
+       unsigned j;
+
+       if(boardtype.n_aochan > MAX_N_AO_CHAN)
+       {
+               printk("bug! boardtype.n_aochan > MAX_N_AO_CHAN\n");
+               return -EINVAL;
+       }
 
-       if(alloc_subdevices(dev, 10) < 0)
+       if(alloc_subdevices(dev, 11 + NUM_GPCT) < 0)
                return -ENOMEM;
 
        /* analog input subdevice */
@@ -2687,54 +3511,65 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        dev->read_subdev=s;
        if(boardtype.n_adchan){
                s->type=COMEDI_SUBD_AI;
-               s->subdev_flags=SDF_READABLE|SDF_DIFF;
-               if(boardtype.reg_type == ni_reg_normal)
+               s->subdev_flags=SDF_READABLE | SDF_DIFF | SDF_DITHER | SDF_CMD_READ;
+               if(boardtype.reg_type != ni_reg_611x)
                        s->subdev_flags |= SDF_GROUND | SDF_COMMON | SDF_OTHER;
-               s->subdev_flags|=SDF_DITHER;
+               if(boardtype.adbits > 16)
+                       s->subdev_flags |= SDF_LSAMPL;
+               if(boardtype.reg_type & ni_reg_m_series_mask)
+                       s->subdev_flags |= SDF_SOFT_CALIBRATED;
                s->n_chan=boardtype.n_adchan;
                s->len_chanlist=512;
                s->maxdata=(1<<boardtype.adbits)-1;
                s->range_table=ni_range_lkup[boardtype.gainlkup];
-               s->insn_read=ni_ai_insn_read;
-               s->insn_config=ni_ai_insn_config;
-               s->do_cmdtest=ni_ai_cmdtest;
-               s->do_cmd=ni_ai_cmd;
-               s->cancel=ni_ai_reset;
-               s->poll=ni_ai_poll;
-               s->munge=ni_ai_munge;
+               s->insn_read = &ni_ai_insn_read;
+               s->insn_config = &ni_ai_insn_config;
+               s->do_cmdtest = &ni_ai_cmdtest;
+               s->do_cmd = &ni_ai_cmd;
+               s->cancel = &ni_ai_reset;
+               s->poll = &ni_ai_poll;
+               s->munge = &ni_ai_munge;
+#ifdef PCIDMA
+               s->async_dma_dir = DMA_FROM_DEVICE;
+#endif
        }else{
                s->type=COMEDI_SUBD_UNUSED;
        }
 
        /* analog output subdevice */
 
-       s=dev->subdevices+1;
+       s = dev->subdevices + 1;
        if(boardtype.n_aochan){
-               dev->write_subdev=s;
-               s->type=COMEDI_SUBD_AO;
-               s->subdev_flags=SDF_WRITABLE|SDF_DEGLITCH|SDF_GROUND;
-               s->n_chan=boardtype.n_aochan;
-               s->maxdata=(1<<boardtype.aobits)-1;
-               if(boardtype.ao_unipolar){
-                       s->range_table=&range_ni_E_ao_ext;      /* XXX wrong for some boards */
-               }else{
-                       s->range_table=&range_bipolar10;
-               }
-               s->insn_read=ni_ao_insn_read;
+               s->type = COMEDI_SUBD_AO;
+               s->subdev_flags = SDF_WRITABLE | SDF_DEGLITCH | SDF_GROUND;
+               if(boardtype.reg_type & ni_reg_m_series_mask)
+                       s->subdev_flags |= SDF_SOFT_CALIBRATED;
+               s->n_chan = boardtype.n_aochan;
+               s->maxdata = (1 << boardtype.aobits) - 1;
+               s->range_table = boardtype.ao_range_table;
+               s->insn_read = &ni_ao_insn_read;
                if(boardtype.reg_type & ni_reg_6xxx_mask){
-                       s->insn_write=ni_ao_insn_write_671x;
+                       s->insn_write = &ni_ao_insn_write_671x;
                }else{
-                       s->insn_write=ni_ao_insn_write;
+                       s->insn_write = &ni_ao_insn_write;
                }
+#ifdef PCIDMA
+               if(boardtype.n_aochan){
+                       s->async_dma_dir = DMA_TO_DEVICE;
+#else
                if(boardtype.ao_fifo_depth){
-                       s->do_cmd=ni_ao_cmd;
-                       s->do_cmdtest=ni_ao_cmdtest;
-                       s->len_chanlist = 2;
-                       s->munge=ni_ao_munge;
+#endif
+                       dev->write_subdev=s;
+                       s->subdev_flags |= SDF_CMD_WRITE;
+                       s->do_cmd = &ni_ao_cmd;
+                       s->do_cmdtest = &ni_ao_cmdtest;
+                       s->len_chanlist = boardtype.n_aochan;
+                       if((boardtype.reg_type & ni_reg_m_series_mask) == 0)
+                               s->munge=ni_ao_munge;
                }
-               s->cancel=ni_ao_reset;
+               s->cancel = &ni_ao_reset;
        }else{
-               s->type=COMEDI_SUBD_UNUSED;
+               s->type = COMEDI_SUBD_UNUSED;
        }
        if((boardtype.reg_type & ni_reg_67xx_mask))
                init_ao_67xx(dev, s);
@@ -2744,17 +3579,23 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        s=dev->subdevices+2;
        s->type=COMEDI_SUBD_DIO;
        s->subdev_flags=SDF_WRITABLE|SDF_READABLE;
-       s->n_chan=8;
        s->maxdata=1;
-       s->range_table=&range_digital;
        s->io_bits=0;           /* all bits input */
-       s->insn_bits=ni_dio_insn_bits;
-       s->insn_config=ni_dio_insn_config;
+       s->range_table=&range_digital;
+       s->n_chan = boardtype.num_p0_dio_channels;
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+       {
+               s->insn_bits = ni_m_series_dio_insn_bits;
+               s->insn_config=ni_m_series_dio_insn_config;
+               ni_writel(s->io_bits, M_Offset_DIO_Direction);
+       }else
+       {
+               s->insn_bits=ni_dio_insn_bits;
+               s->insn_config=ni_dio_insn_config;
+               devpriv->dio_control = DIO_Pins_Dir(s->io_bits);
+               ni_writew(devpriv->dio_control, DIO_Control_Register);
+       }
 
-       /* dio setup */
-       devpriv->dio_control = DIO_Pins_Dir(s->io_bits);
-       win_out(devpriv->dio_control,DIO_Control_Register);
-       
        /* 8255 device */
        s=dev->subdevices+3;
        if(boardtype.has_8255){
@@ -2763,41 +3604,68 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
                s->type=COMEDI_SUBD_UNUSED;
        }
 
-       /* general purpose counter/timer device */
+       /* formerly general purpose counter/timer device, but no longer used */
        s=dev->subdevices+4;
-       s->type=COMEDI_SUBD_COUNTER;
-       s->subdev_flags=SDF_READABLE|SDF_WRITABLE;
-       s->insn_read=  ni_gpct_insn_read;
-       s->insn_write= ni_gpct_insn_write;
-       s->insn_config=ni_gpct_insn_config;
-       s->n_chan=2;
-       s->maxdata=1;
-       devpriv->an_trig_etc_reg = 0;
-       GPCT_Reset(dev,0);
-       GPCT_Reset(dev,1);
+       s->type = COMEDI_SUBD_UNUSED;
 
        /* calibration subdevice -- ai and ao */
        s=dev->subdevices+5;
        s->type=COMEDI_SUBD_CALIB;
-       s->subdev_flags=SDF_WRITABLE|SDF_INTERNAL;
-       s->insn_read=ni_calib_insn_read;
-       s->insn_write=ni_calib_insn_write;
-       caldac_setup(dev,s);
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+       {
+               // internal PWM analog output used for AI nonlinearity calibration
+               s->subdev_flags = SDF_INTERNAL;
+               s->insn_config = &ni_m_series_pwm_config;
+               s->n_chan = 1;
+               s->maxdata = 0;
+               ni_writel(0x0, M_Offset_Cal_PWM);
+       } else if(boardtype.reg_type == ni_reg_6143)
+       {
+               // internal PWM analog output used for AI nonlinearity calibration
+               s->subdev_flags = SDF_INTERNAL;
+               s->insn_config = &ni_6143_pwm_config;
+               s->n_chan = 1;
+               s->maxdata = 0;
+       }else
+       {
+               s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
+               s->insn_read = &ni_calib_insn_read;
+               s->insn_write = &ni_calib_insn_write;
+               caldac_setup(dev, s);
+       }
 
        /* EEPROM */
        s=dev->subdevices+6;
        s->type=COMEDI_SUBD_MEMORY;
        s->subdev_flags=SDF_READABLE|SDF_INTERNAL;
-       s->n_chan=512;
        s->maxdata=0xff;
-       s->insn_read=ni_eeprom_insn_read;
-
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+       {
+               s->n_chan = M_SERIES_EEPROM_SIZE;
+               s->insn_read = &ni_m_series_eeprom_insn_read;
+       }else
+       {
+               s->n_chan = 512;
+               s->insn_read = &ni_eeprom_insn_read;
+       }
        /* PFI */
-       s=dev->subdevices+7;
-       s->type=COMEDI_SUBD_DIO;
-       s->subdev_flags=SDF_READABLE|SDF_WRITABLE|SDF_INTERNAL;
-       s->n_chan=10;
-       s->maxdata=1;
+       s=dev->subdevices + 7;
+       s->type = COMEDI_SUBD_DIO;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+       {
+               unsigned i;
+               s->n_chan = 16;
+               ni_writew(s->state, M_Offset_PFI_DO);
+               for(i = 0; i < NUM_PFI_OUTPUT_SELECT_REGS; ++i)
+               {
+                       ni_writew(devpriv->pfi_output_select_reg[i], M_Offset_PFI_Output_Select(i + 1));
+               }
+       }else
+       {
+               s->n_chan = 10;
+       }
+       s->maxdata = 1;
        s->insn_bits = ni_pfi_insn_bits;
        s->insn_config = ni_pfi_insn_config;
        ni_set_bits(dev, IO_Bidirection_Pin_Register, ~0, 0);
@@ -2830,9 +3698,57 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        devpriv->serial_interval_ns = 0;
        devpriv->serial_hw_mode = 0;
 
+       /* RTSI */
+       s=dev->subdevices + 10;
+       s->type = COMEDI_SUBD_DIO;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+       s->n_chan = 8;
+       s->maxdata = 1;
+       s->insn_bits = ni_rtsi_insn_bits;
+       s->insn_config = ni_rtsi_insn_config;
+       ni_rtsi_init(dev);
+
+       /* General purpose counters */
+       for(j = 0; j < NUM_GPCT; ++j)
+       {
+               s = dev->subdevices + 11 + j;
+               s->type = COMEDI_SUBD_COUNTER;
+               s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+               s->n_chan = 3;
+               if(boardtype.reg_type & ni_reg_m_series_mask)
+                       s->maxdata = 0xffffffff;
+               else
+                       s->maxdata = 0xffffff;
+               s->insn_read = ni_gpct_insn_read;
+               s->insn_write = ni_gpct_insn_write;
+               s->insn_config = ni_gpct_insn_config;
+               s->do_cmd = ni_gpct_cmd;
+               s->do_cmdtest = ni_gpct_cmdtest;
+               s->cancel = ni_gpct_cancel;
+               s->async_dma_dir = DMA_BIDIRECTIONAL;
+               s->private = &devpriv->counters[j];
+
+               devpriv->counters[j].dev = dev;
+               devpriv->counters[j].chip_index = 0;
+               devpriv->counters[j].counter_index = j;
+               devpriv->counters[j].write_register = ni_gpct_write_register;
+               devpriv->counters[j].read_register = ni_gpct_read_register;
+               if(boardtype.reg_type & ni_reg_m_series_mask)
+               {
+                       devpriv->counters[j].variant = ni_gpct_variant_m_series;
+               }else
+               {
+                       devpriv->counters[j].variant = ni_gpct_variant_e_series;
+               }
+               devpriv->counters[j].clock_period_ps = 0;
+               devpriv->counters[j].mite_chan = NULL;
+               ni_tio_init_counter(&devpriv->counters[j]);
+       }
+
        /* ai configuration */
        ni_ai_reset(dev,dev->subdevices+0);
-       if(boardtype.reg_type == ni_reg_normal){
+       if((boardtype.reg_type & ni_reg_6xxx_mask) == 0){
+               // BEAM is this needed for PCI-6143 ??
                devpriv->clock_and_fout =
                        Slow_Internal_Time_Divide_By_2 |
                        Slow_Internal_Timebase |
@@ -2847,13 +3763,13 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
                        Clock_To_Board_Divide_By_2 |
                        Clock_To_Board;
        }
-       win_out(devpriv->clock_and_fout, Clock_and_FOUT_Register);
+       devpriv->stc_writew(dev, devpriv->clock_and_fout, Clock_and_FOUT_Register);
 
        /* analog output configuration */
        ni_ao_reset(dev,dev->subdevices + 1);
 
        if(dev->irq){
-               win_out((IRQ_POLARITY?Interrupt_Output_Polarity:0) |
+               devpriv->stc_writew(dev, (IRQ_POLARITY?Interrupt_Output_Polarity:0) |
                        (Interrupt_Output_On_3_Pins&0) |
                        Interrupt_A_Enable |
                        Interrupt_B_Enable |
@@ -2864,24 +3780,24 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        }
 
        /* DMA setup */
-       /* 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);
-
-       /* 611x init */
-       if(boardtype.reg_type != ni_reg_normal)
+       ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
+       ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select);
+
+       if(boardtype.reg_type & ni_reg_6xxx_mask)
        {
                ni_writeb( 0, Magic_611x );
+       }else if(boardtype.reg_type & ni_reg_m_series_mask)
+       {
+               int channel;
+               for(channel = 0; channel < boardtype.n_aochan; ++channel)
+               {
+                       ni_writeb(0xf, M_Offset_AO_Waveform_Order(channel));
+                       ni_writeb(0x0, M_Offset_AO_Reference_Attenuation(channel));
+               }
+               ni_writeb(0x0, M_Offset_AO_Calibration);
        }
 
        printk("\n");
-
        return 0;
 }
 
@@ -2937,6 +3853,139 @@ static int ni_read_eeprom(comedi_device *dev,int addr)
        return bitstring;
 }
 
+static int ni_m_series_eeprom_insn_read(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data)
+{
+       data[0] = devpriv->eeprom_buffer[CR_CHAN(insn->chanspec)];
+
+       return 1;
+}
+
+static int ni_get_pwm_config(comedi_device *dev, lsampl_t *data)
+{
+       data[1] = devpriv->pwm_up_count * devpriv->clock_ns;
+       data[2] = devpriv->pwm_down_count * devpriv->clock_ns;
+       return 3;
+}
+
+static int ni_m_series_pwm_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+       unsigned up_count, down_count;
+       switch(data[0])
+       {
+       case INSN_CONFIG_PWM_OUTPUT:
+               switch(data[1])
+               {
+               case TRIG_ROUND_NEAREST:
+                       up_count = (data[2] + devpriv->clock_ns / 2) / devpriv->clock_ns;
+                       break;
+               case TRIG_ROUND_DOWN:
+                       up_count = data[2] / devpriv->clock_ns;
+                       break;
+               case TRIG_ROUND_UP:
+                       up_count = (data[2] + devpriv->clock_ns - 1) / devpriv->clock_ns;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+               }
+               switch(data[3])
+               {
+               case TRIG_ROUND_NEAREST:
+                       down_count = (data[4] + devpriv->clock_ns / 2) / devpriv->clock_ns;
+                       break;
+               case TRIG_ROUND_DOWN:
+                       down_count = data[4] / devpriv->clock_ns;
+                       break;
+               case TRIG_ROUND_UP:
+                       down_count = (data[4] + devpriv->clock_ns - 1) / devpriv->clock_ns;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+               }
+               if(up_count * devpriv->clock_ns != data[2] ||
+                       down_count * devpriv->clock_ns != data[4])
+               {
+                       data[2] = up_count * devpriv->clock_ns;
+                       data[4] = down_count * devpriv->clock_ns;
+                       return -EAGAIN;
+               }
+               ni_writel(MSeries_Cal_PWM_High_Time_Bits(up_count) | MSeries_Cal_PWM_Low_Time_Bits(down_count), M_Offset_Cal_PWM);
+               devpriv->pwm_up_count = up_count;
+               devpriv->pwm_down_count = down_count;
+               return 5;
+               break;
+       case INSN_CONFIG_GET_PWM_OUTPUT:
+               return ni_get_pwm_config(dev, data);
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
+static int ni_6143_pwm_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+       unsigned up_count, down_count;
+       switch(data[0])
+       {
+       case INSN_CONFIG_PWM_OUTPUT:
+               switch(data[1])
+               {
+               case TRIG_ROUND_NEAREST:
+                       up_count = (data[2] + devpriv->clock_ns / 2) / devpriv->clock_ns;
+                       break;
+               case TRIG_ROUND_DOWN:
+                       up_count = data[2] / devpriv->clock_ns;
+                       break;
+               case TRIG_ROUND_UP:
+                       up_count = (data[2] + devpriv->clock_ns - 1) / devpriv->clock_ns;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+               }
+               switch(data[3])
+               {
+               case TRIG_ROUND_NEAREST:
+                       down_count = (data[4] + devpriv->clock_ns / 2) / devpriv->clock_ns;
+                       break;
+               case TRIG_ROUND_DOWN:
+                       down_count = data[4] / devpriv->clock_ns;
+                       break;
+               case TRIG_ROUND_UP:
+                       down_count = (data[4] + devpriv->clock_ns - 1) / devpriv->clock_ns;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+               }
+               if(up_count * devpriv->clock_ns != data[2] ||
+                       down_count * devpriv->clock_ns != data[4])
+               {
+                       data[2] = up_count * devpriv->clock_ns;
+                       data[4] = down_count * devpriv->clock_ns;
+                       return -EAGAIN;
+               }
+               ni_writel(up_count, Calibration_HighTime_6143);
+               devpriv->pwm_up_count = up_count;
+               ni_writel(down_count, Calibration_LowTime_6143);
+               devpriv->pwm_down_count = down_count;
+               return 5;
+               break;
+       case INSN_CONFIG_GET_PWM_OUTPUT:
+               return ni_get_pwm_config(dev, data);
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
 static void ni_write_caldac(comedi_device *dev,int addr,int val);
 /*
        calibration subdevice
@@ -3095,7 +4144,7 @@ static int pack_dac8043(int addr,int val,int *bitstring)
        *bitstring=val&0xfff;
        return 12;
 }
-       
+
 static int pack_ad8522(int addr,int val,int *bitstring)
 {
        *bitstring=(val&0xfff)|(addr ? 0xc000:0xa000);
@@ -3115,601 +4164,626 @@ static int pack_ad8842(int addr,int val,int *bitstring)
 }
 
 
-
-
-
-/*
- *
- *  General Purpose Counter/Timer section
- *
- */
-
-/*
- * Low level stuff...Each STC counter has two 24 bit load registers
- * (A&B).  Just make it easier to access them.
- *
- * These are inlined _only_ because they are used once in subsequent
- * code.  Otherwise they should not be inlined.
- */
-static inline void GPCT_Load_A(comedi_device *dev, int chan, unsigned int value)
-{
-       win_out2( value & 0x00ffffff, G_Load_A_Register(chan));
-}
-
-static inline void GPCT_Load_B(comedi_device *dev, int chan, unsigned int value)
-{
-       win_out2( value & 0x00ffffff, G_Load_B_Register(chan));
-}
-
-/*  Load a value into the counter, using register A as the intermediate step.
-*  You might use GPCT_Load_Using_A to load a 0x000000 into a counter
-*  reset its value.
-*/
-static void GPCT_Load_Using_A(comedi_device *dev, int chan, unsigned int value)
-{
-       devpriv->gpct_mode[chan] &= (~G_Load_Source_Select);
-       win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
-       GPCT_Load_A(dev,chan,value);
-       win_out( devpriv->gpct_command[chan]|G_Load,G_Command_Register(chan));
-}
-
+#if 0
 /*
- *     Read the GPCTs current value.  
+ *     Read the GPCTs current value.
  */
 static int GPCT_G_Watch(comedi_device *dev, int chan)
 {
        unsigned int hi1,hi2,lo;
-       
+
        devpriv->gpct_command[chan] &= ~G_Save_Trace;
-       win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
-       
+       devpriv->stc_writew(dev,  devpriv->gpct_command[chan],G_Command_Register(chan));
+
        devpriv->gpct_command[chan] |= G_Save_Trace;
-       win_out( devpriv->gpct_command[chan], G_Command_Register(chan));
+       devpriv->stc_writew(dev,  devpriv->gpct_command[chan], G_Command_Register(chan));
 
        /* This procedure is used because the two registers cannot
         * be read atomically. */
        do{
-               hi1 = win_in( G_Save_Register_High(chan));
-               lo = win_in(G_Save_Register_Low(chan));
-               hi2 = win_in( G_Save_Register_High(chan));
+               hi1 = devpriv->stc_readw(dev,  G_Save_Register_High(chan));
+               lo = devpriv->stc_readw(dev, G_Save_Register_Low(chan));
+               hi2 = devpriv->stc_readw(dev,  G_Save_Register_High(chan));
        }while(hi1!=hi2);
 
        return (hi1<<16)|lo;
 }
 
-
-static int GPCT_Disarm(comedi_device *dev, int chan)
+static void GPCT_Reset(comedi_device *dev, int chan)
 {
-       win_out( devpriv->gpct_command[chan] | G_Disarm,G_Command_Register(chan));
-       return 0;
-}
+       int temp_ack_reg=0;
 
+       //printk("GPCT_Reset...");
+       devpriv->gpct_cur_operation[chan] = GPCT_RESET;
 
-static int GPCT_Arm(comedi_device *dev, int chan)
-{
-       win_out( devpriv->gpct_command[chan] | G_Arm,G_Command_Register(chan));
-       /* If the counter is doing pulse width measurement, then make
-        sure that the counter did not start counting right away.  This would
-        indicate that we started acquiring the pulse after it had already 
-        started and our measurement would be inaccurate */
-       if(devpriv->gpct_cur_operation[chan] == GPCT_SINGLE_PW){
-               int g_status; 
+       switch (chan) {
+               case 0:
+                       devpriv->stc_writew(dev, G0_Reset,Joint_Reset_Register);
+                       ni_set_bits(dev,Interrupt_A_Enable_Register,G0_TC_Interrupt_Enable,  0);
+                       ni_set_bits(dev,Interrupt_A_Enable_Register,G0_Gate_Interrupt_Enable,0);
+                       temp_ack_reg |= G0_Gate_Error_Confirm;
+                       temp_ack_reg |= G0_TC_Error_Confirm;
+                       temp_ack_reg |= G0_TC_Interrupt_Ack;
+                       temp_ack_reg |= G0_Gate_Interrupt_Ack;
+                       devpriv->stc_writew(dev, temp_ack_reg,Interrupt_A_Ack_Register);
 
-               g_status=win_in(G_Status_Register);
-               
-               if(chan == 0){
-                       //TIM 5/2/01 possible error with very short pulses
-                       if((G0_Counting_St & g_status)|| !(G0_Armed_St&g_status)) {
-                               //error: we missed the beginning of the pulse
-                               return -EINVAL; //there is probably a more accurate error code...
-                       }
-               }else{
-                       if((G1_Counting_St & g_status)|| !(G1_Armed_St&g_status)) {
-                               //error: we missed the beginning of the pulse
-                               return -EINVAL;
-                       }
-               }
-       }
-       return 0;
-}
+                       //problem...this interferes with the other ctr...
+                       devpriv->an_trig_etc_reg |= GPFO_0_Output_Enable;
+                       devpriv->stc_writew(dev, devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
+                       break;
+               case 1:
+                       devpriv->stc_writew(dev, G1_Reset,Joint_Reset_Register);
+                       ni_set_bits(dev,Interrupt_B_Enable_Register,G1_TC_Interrupt_Enable,  0);
+                       ni_set_bits(dev,Interrupt_B_Enable_Register,G0_Gate_Interrupt_Enable,0);
+                       temp_ack_reg |= G1_Gate_Error_Confirm;
+                       temp_ack_reg |= G1_TC_Error_Confirm;
+                       temp_ack_reg |= G1_TC_Interrupt_Ack;
+                       temp_ack_reg |= G1_Gate_Interrupt_Ack;
+                       devpriv->stc_writew(dev, temp_ack_reg,Interrupt_B_Ack_Register);
 
-static int GPCT_Set_Source(comedi_device *dev,int chan ,int source)
-{
-       //printk("GPCT_Set_Source...");
-       devpriv->gpct_input_select[chan] &= ~G_Source_Select(0x1f);//reset gate to 0
-       switch(source) {
-               case GPCT_INT_CLOCK:
-               devpriv->gpct_input_select[chan] |= G_Source_Select(0);//INT_TIMEBASE
-               break;
-       case GPCT_EXT_PIN:
-               if(chan==0)
-                       devpriv->gpct_input_select[chan] |= G_Source_Select(9);//PFI8
-               else
-                       devpriv->gpct_input_select[chan] |= G_Source_Select(4);//PFI3
-               break;
-       default:
-               return -EINVAL;
-       }
-       win_out(devpriv->gpct_input_select[chan], G_Input_Select_Register(chan));
-       //printk("exit GPCT_Set_Source\n");
-       return 0;
+                       devpriv->an_trig_etc_reg |= GPFO_1_Output_Enable;
+                       devpriv->stc_writew(dev, devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
+                       break;
+       };
+
+       devpriv->gpct_mode[chan] = 0;
+       devpriv->gpct_input_select[chan] = 0;
+       devpriv->gpct_command[chan] = 0;
+
+       devpriv->gpct_command[chan] |= G_Synchronized_Gate;
+
+       devpriv->stc_writew(dev,  devpriv->gpct_mode[chan],G_Mode_Register(chan));
+       devpriv->stc_writew(dev,  devpriv->gpct_input_select[chan],G_Input_Select_Register(chan));
+       devpriv->stc_writew(dev,  0,G_Autoincrement_Register(chan));
+
+       //printk("exit GPCT_Reset\n");
 }
 
-static int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate)
+#endif
+
+static int ni_gpct_insn_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
 {
-       //printk("GPCT_Set_Gate...");
-       devpriv->gpct_input_select[chan] &= ~G_Gate_Select(0x1f);//reset gate to 0
-       switch(gate) {
-       case GPCT_NO_GATE:
-               devpriv->gpct_input_select[chan] |= G_Gate_Select(31);//Low
-               devpriv->gpct_mode[chan] |= G_Gate_Polarity;
-               break;
-       case GPCT_EXT_PIN:
-               devpriv->gpct_mode[chan] &= ~G_Gate_Polarity;
-               if(chan==0){
-                       devpriv->gpct_input_select[chan] |= G_Gate_Select(10);//PFI9
-               }else{
-                       devpriv->gpct_input_select[chan] |= G_Gate_Select(5);//PFI4
-               }
-               break;
-       default:
-               return -EINVAL;
-       }
-       win_out(devpriv->gpct_input_select[chan], G_Input_Select_Register(chan));
-       win_out(devpriv->gpct_mode[chan], G_Mode_Register(chan));
-       //printk("exit GPCT_Set_Gate\n");
-       return 0;
+       struct ni_gpct *counter = s->private;
+       return ni_tio_insn_config(counter, insn, data);
 }
 
-static int GPCT_Set_Direction(comedi_device *dev,int chan,int direction)
+static int ni_gpct_insn_read(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data)
 {
-       //printk("GPCT_Set_Direction...");
-       
-       devpriv->gpct_command[chan] &= ~G_Up_Down(0x3);
-       switch (direction) {
-               case GPCT_UP:
-                       devpriv->gpct_command[chan] |= G_Up_Down(1);
-                       break;
-               case GPCT_DOWN:
-                       devpriv->gpct_command[chan] |= G_Up_Down(0);
-                       break;
-               case GPCT_HWUD:
-                       devpriv->gpct_command[chan] |= G_Up_Down(2);
-                       break;
-               default:
-                       printk("Error direction=0x%08x..",direction);
-                       return -EINVAL;
-       }
-       win_out(devpriv->gpct_command[chan], G_Command_Register(chan));
-       //TIM 4/23/01 win_out(devpriv->gpct_mode[chan], G_Mode_Register(chan));
-       //printk("exit GPCT_Set_Direction\n");
-       return 0;
+       struct ni_gpct *counter = s->private;
+       return ni_tio_rinsn(counter, insn, data);
 }
 
-static void GPCT_Event_Counting(comedi_device *dev,int chan)
-{
-
-       //NOTE: possible residual bits from multibit masks can corrupt
-       //If you config for several measurements between Resets, watch out!
-       
-       //printk("GPCT_Event_Counting...");
-       
-       devpriv->gpct_cur_operation[chan] = GPCT_SIMPLE_EVENT;
-       
-       // Gating_Mode = 1
-       devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Gating_Mode(1);
-       
-       // Trigger_Mode_For_Edge_Gate = 1
-       devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
-       devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);
-
-       win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
-       //printk("exit GPCT_Event_Counting\n");
-}
-
-static void GPCT_Period_Meas(comedi_device *dev, int chan)
+static int ni_gpct_insn_write(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
 {
-       //printk("GPCT_Period_Meas...");
-       
-       devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PERIOD;
+       struct ni_gpct *counter = s->private;
+       return ni_tio_winsn(counter, insn, data);
+}
 
-       
-       //NOTE: possible residual bits from multibit masks can corrupt
-       //If you config for several measurements between Resets, watch out!     
-       devpriv->gpct_mode[chan] &= ~G_OR_Gate;
-       devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;
-       
-       // Output_Mode = 3 
-       devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Output_Mode(3);
-       
-       
-       //Gating Mode=2
-       devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Gating_Mode(2);
-       
-       // Trigger_Mode_For_Edge_Gate=0
-       devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
-       devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(0);
-
-       devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;
-       devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;
-       devpriv->gpct_mode[chan] &= ~G_Loading_On_TC;
-       devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;
-
-       // Stop_Mode = 2
-       devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Stop_Mode(0);
-       
-       // Counting_Once = 2 
-       devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
-       devpriv->gpct_mode[chan] |= G_Counting_Once(2);
-
-       // Up_Down = 1 
-       devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));
-       devpriv->gpct_command[chan] |= G_Up_Down(1);
-
-       win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
-       win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
-       //printk("exit GPCT_Period_Meas\n");
-}
-
-static void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan)
-{
-       //printk("GPCT_Pulse_Width_Meas...");
+static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s)
+{
+// XXX set M_Offset_GX_DMA_Config for m-series
+#ifdef PCIDMA
+       struct ni_gpct *counter = s->private;
+       const comedi_cmd *cmd = &s->async->cmd;
+       int retval = ni_request_gpct_mite_channel(dev, counter->counter_index);
+       if(retval)
+       {
+               comedi_error(dev, "no dma channel available for use by counter");
+               return retval;
+       }
+       return ni_tio_cmd(counter, s->async);
+#else
+       return -ENOTSUPP;
+#endif
+}
 
-       devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PW;
+static int ni_gpct_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd)
+{
+       struct ni_gpct *counter = s->private;
+       //XXX check chanlist_len == 1
+       return ni_tio_cmdtest(counter);
+}
 
-       devpriv->gpct_mode[chan] &= ~G_OR_Gate;
-       devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;
+static int ni_gpct_cancel(comedi_device *dev, comedi_subdevice *s)
+{
+       struct ni_gpct *counter = s->private;
+       int retval = ni_tio_cancel(counter);
+       ni_release_gpct_mite_channel(dev, counter->counter_index);
+       return retval;
+}
 
-       // Output_Mode = 3 
-       devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Output_Mode(3);
-       
-       //Gating Mode=1
-       devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Gating_Mode(1);//TIM 4/24/01 was 2
-       
-       // Trigger_Mode_For_Edge_Gate=2
-       devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
-       devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);//TIM 4/24/01 was 0
-
-
-       devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;//TIM 4/24/01 was 1
-       devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;//TIM 4/24/01 was 0
-
-       devpriv->gpct_mode[chan] &= ~G_Loading_On_TC;
-       devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;
-
-       // Stop_Mode = 0
-       devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Stop_Mode(0);
-       
-       // Counting_Once = 2 
-       devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
-       devpriv->gpct_mode[chan] |= G_Counting_Once(2);
-
-       // Up_Down = 1 
-       devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));
-       devpriv->gpct_command[chan] |= G_Up_Down(1);
-
-       win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
-       win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
-
-       //printk("exit GPCT_Pulse_Width_Meas\n");
-}
-
-/* GPCT_Gen_Single_Pulse() creates pulse of length pulsewidth which starts after the Arm
-signal is sent.  The pulse is delayed by the value already in the counter.  This function could
-be modified to send a pulse in response to a trigger event at its gate.*/
-static void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length)
-{
-       //printk("GPCT_Gen_Cont...");
-
-       devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PULSE_OUT;
-
-       // Set length of the pulse
-       GPCT_Load_B(dev,chan, length-1);
-
-       //Load next time using B, This is reset by GPCT_Load_Using_A()
-       devpriv->gpct_mode[chan] |= G_Load_Source_Select;
-       
-       devpriv->gpct_mode[chan] &= ~G_OR_Gate;
-       devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;
-
-       // Output_Mode = 3 
-       devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Output_Mode(2); //TIM 4/26/01 was 3
-       
-       //Gating Mode=0 for untriggered single pulse
-       devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Gating_Mode(0); //TIM 4/25/01 was 1
-       
-       // Trigger_Mode_For_Edge_Gate=0
-       devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
-       devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);
+/*
+ *
+ *  Programmable Function Inputs
+ *
+ */
 
+static int ni_m_series_set_pfi_routing(comedi_device *dev, unsigned chan, unsigned source)
+{
+       unsigned pfi_reg_index;
+       unsigned array_offset;
+       if((source & 0x1f) != source) return -EINVAL;
+       pfi_reg_index = 1 + chan / 3;
+       array_offset = pfi_reg_index - 1;
+       devpriv->pfi_output_select_reg[array_offset] &= ~MSeries_PFI_Output_Select_Mask(chan);
+       devpriv->pfi_output_select_reg[array_offset] |= MSeries_PFI_Output_Select_Bits(chan, source);
+       ni_writew(devpriv->pfi_output_select_reg[array_offset], M_Offset_PFI_Output_Select(pfi_reg_index));
+       return 2;
+}
 
-       devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;
-       devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;
-       devpriv->gpct_mode[chan] |= G_Loading_On_TC; //TIM 4/25/01
-       devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;
+static int ni_old_set_pfi_routing(comedi_device *dev, unsigned chan, unsigned source)
+{
+       // pre-m-series boards have fixed signals on pfi pins
+       if(source != ni_old_get_pfi_routing(dev, chan)) return -EINVAL;
+       return 2;
+}
 
-       // Stop_Mode = 2
-       devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Stop_Mode(2); //TIM 4/25/01
-       
-       // Counting_Once = 2 
-       devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
-       devpriv->gpct_mode[chan] |= G_Counting_Once(1); //TIM 4/25/01
+static int ni_set_pfi_routing(comedi_device *dev, unsigned chan, unsigned source)
+{
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+               return ni_m_series_set_pfi_routing(dev, chan, source);
+       else
+               return ni_old_set_pfi_routing(dev, chan, source);
+}
 
-       // Up_Down = 1 
-       devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));
-       devpriv->gpct_command[chan] |= G_Up_Down(0); //TIM 4/25/01 was 1
+static unsigned ni_m_series_get_pfi_routing(comedi_device *dev, unsigned chan)
+{
+       const unsigned array_offset = chan / 3;
+       return MSeries_PFI_Output_Select_Source(chan, devpriv->pfi_output_select_reg[array_offset]);
+}
 
-       win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
-       win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
+static unsigned ni_old_get_pfi_routing(comedi_device *dev, unsigned chan)
+{
+       // pre-m-series boards have fixed signals on pfi pins
+       switch(chan)
+       {
+       case 0:
+               return NI_PFI_OUTPUT_AI_START1;
+               break;
+       case 1:
+               return NI_PFI_OUTPUT_AI_START2;
+               break;
+       case 2:
+               return NI_PFI_OUTPUT_AI_CONVERT;
+               break;
+       case 3:
+               return NI_PFI_OUTPUT_G_SRC1;
+               break;
+       case 4:
+               return NI_PFI_OUTPUT_G_GATE1;
+               break;
+       case 5:
+               return NI_PFI_OUTPUT_AO_UPDATE_N;
+               break;
+       case 6:
+               return NI_PFI_OUTPUT_AO_START1;
+               break;
+       case 7:
+               return NI_PFI_OUTPUT_AI_START_PULSE;
+               break;
+       case 8:
+               return NI_PFI_OUTPUT_G_SRC0;
+               break;
+       case 9:
+               return NI_PFI_OUTPUT_G_GATE0;
+               break;
+       default:
+               rt_printk("%s: bug, unhandled case in switch.\n", __FUNCTION__);
+               break;
+       }
+       return 0;
+}
 
-       //printk("exit GPCT_Gen_Cont\n");
+static unsigned ni_get_pfi_routing(comedi_device *dev, unsigned chan)
+{
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+               return ni_m_series_get_pfi_routing(dev, chan);
+       else
+               return ni_old_get_pfi_routing(dev, chan);
 }
 
-static void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length)
+static int ni_pfi_insn_bits(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data)
 {
-       //printk("GPCT_Gen_Cont...");
+       if((boardtype.reg_type & ni_reg_m_series_mask) == 0)
+       {
+               data[1] = 0;
+               return 2;
+       }
+       if(data[0])
+       {
+               s->state &= ~data[0];
+               s->state |= (data[0] & data[1]);
+               ni_writew(s->state, M_Offset_PFI_DO);
+       }
+       data[1] = ni_readw(M_Offset_PFI_DI);
+       return 2;
+}
 
-       devpriv->gpct_cur_operation[chan] = GPCT_CONT_PULSE_OUT;
+static int ni_pfi_insn_config(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data)
+{
+       unsigned int chan;
 
-       // Set length of the pulse
-       GPCT_Load_B(dev,chan, length-1);
+       if(insn->n < 1)return -EINVAL;
 
-       //Load next time using B, This is reset by GPCT_Load_Using_A()
-       devpriv->gpct_mode[chan] |= G_Load_Source_Select;
-       
-       devpriv->gpct_mode[chan] &= ~G_OR_Gate;
-       devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;
+       chan = CR_CHAN(insn->chanspec);
 
-       // Output_Mode = 3 
-       devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Output_Mode(2); //TIM 4/26/01 was 3
-       
-       //Gating Mode=0 for untriggered single pulse
-       devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Gating_Mode(0); //TIM 4/26/01 was 0
-       
-       // Trigger_Mode_For_Edge_Gate=0
-       devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
-       devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);
+       switch(data[0]){
+       case COMEDI_OUTPUT:
+               ni_set_bits(dev, IO_Bidirection_Pin_Register, 1<<chan, 1);
+               break;
+       case COMEDI_INPUT:
+               ni_set_bits(dev, IO_Bidirection_Pin_Register, 1<<chan, 0);
+               break;
+       case INSN_CONFIG_DIO_QUERY:
+               data[1] = (devpriv->io_bidirection_pin_reg & (1<<chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
+               return insn->n;
+               break;
+       case INSN_CONFIG_SET_ROUTING:
+               return ni_set_pfi_routing(dev, chan, data[1]);
+               break;
+       case INSN_CONFIG_GET_ROUTING:
+               data[1] = ni_get_pfi_routing(dev, chan);
+               return 2;
+               break;
+       default:
+               return -EINVAL;
+       }
 
+       return 1;
+}
 
-       devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;
-       devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;
-       devpriv->gpct_mode[chan] |= G_Loading_On_TC; 
-       devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;
+/*
+ *
+ *  NI RTSI Bus Functions
+ *
+ */
+static void ni_rtsi_init(comedi_device *dev)
+{
+       // Initialises the RTSI bus signal switch to a default state
 
-       // Stop_Mode = 2
-       devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
-       devpriv->gpct_mode[chan] |= G_Stop_Mode(0); //TIM 4/26/01
-       
-       // Counting_Once = 2 
-       devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
-       devpriv->gpct_mode[chan] |= G_Counting_Once(0); //TIM 4/26/01
+       // Set clock mode to internal
+       devpriv->clock_and_fout2 = MSeries_RTSI_10MHz_Bit;
+       if(ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0)
+       {
+               rt_printk("ni_set_master_clock failed, bug?");
+       }
+       // default internal lines routing to RTSI bus lines
+       devpriv->rtsi_trig_a_output_reg = RTSI_Trig_Output_Bits(0, NI_RTSI_OUTPUT_ADR_START1) |
+               RTSI_Trig_Output_Bits(1, NI_RTSI_OUTPUT_ADR_START2) |
+               RTSI_Trig_Output_Bits(2, NI_RTSI_OUTPUT_SCLKG) |
+               RTSI_Trig_Output_Bits(3, NI_RTSI_OUTPUT_DACUPDN);
+       devpriv->stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
+               RTSI_Trig_A_Output_Register);
+       devpriv->rtsi_trig_b_output_reg = RTSI_Trig_Output_Bits(4, NI_RTSI_OUTPUT_DA_START1) |
+               RTSI_Trig_Output_Bits(5, NI_RTSI_OUTPUT_G_SRC0) |
+               RTSI_Trig_Output_Bits(6, NI_RTSI_OUTPUT_G_GATE0);
+       if(boardtype.reg_type & ni_reg_m_series_mask)
+               devpriv->rtsi_trig_b_output_reg |= RTSI_Trig_Output_Bits(7, NI_RTSI_OUTPUT_RTSI_OSC);
+       devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
+               RTSI_Trig_B_Output_Register);
+
+       // Sets the source and direction of the 4 on board lines
+//     devpriv->stc_writew(dev, 0x0000, RTSI_Board_Register);
+}
 
-       // Up_Down = 1 
-       devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));
-       devpriv->gpct_command[chan] |= G_Up_Down(0); 
+static int ni_rtsi_insn_bits(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data)
+{
+       if(insn->n != 2) return -EINVAL;
 
-       //TIM 4/26/01
-       //This seems pretty unsafe since I don't think it is cleared anywhere.
-       //I don't think this is working
-       //devpriv->gpct_command[chan] &= ~G_Bank_Switch_Enable;
-       //devpriv->gpct_command[chan] &= ~G_Bank_Switch_Mode;
-       
+       data[1] = 0;
 
-       win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
-       win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
-
-       //printk("exit GPCT_Gen_Cont\n");
+       return 2;
 }
 
-static void GPCT_Reset(comedi_device *dev, int chan)
+/* Find best multiplier/divider to try and get the PLL running at 80 MHz
+ * given an arbitrary frequency input clock */
+static int ni_mseries_get_pll_parameters(unsigned reference_period_ns,
+       unsigned *freq_divider, unsigned *freq_multiplier, unsigned *actual_period_ns)
 {
-       int temp_ack_reg=0;
-       
-       //printk("GPCT_Reset...");
-       devpriv->gpct_cur_operation[chan] = GPCT_RESET;
+       unsigned div;
+       unsigned best_div = 1;
+       static const unsigned max_div = 0x10;
+       unsigned mult;
+       unsigned best_mult = 1;
+       static const unsigned max_mult = 0x100;
+       static const unsigned pico_per_nano = 1000;
+
+       const unsigned reference_picosec = reference_period_ns * pico_per_nano;
+       /* m-series wants the phased-locked loop to output 80MHz, which is divided by 4 to
+        * 20 MHz for most timing clocks */
+       static const unsigned target_picosec = 12500;
+       static const unsigned fudge_factor_80_to_20Mhz = 4;
+       int best_period_picosec = 0;
+       for(div = 1; div <= max_div; ++div)
+       {
+               for(mult = 1; mult <= max_mult; ++mult)
+               {
+                       unsigned new_period_ps = (reference_picosec * div) / mult;
+                       if(abs(new_period_ps - target_picosec) < abs(best_period_picosec - target_picosec))
+                       {
+                               best_period_picosec = new_period_ps;
+                               best_div = div;
+                               best_mult = mult;
+                       }
+               }
+       }
+       if(best_period_picosec == 0)
+       {
+               rt_printk("%s: bug, failed to find pll parameters\n", __FUNCTION__);
+               return -EIO;
+       }
+       *freq_divider = best_div;
+       *freq_multiplier = best_mult;
+       *actual_period_ns = (best_period_picosec * fudge_factor_80_to_20Mhz + (pico_per_nano / 2)) / pico_per_nano;
+       return 0;
+}
 
-       switch (chan) {
-               case 0:
-                       win_out(G0_Reset,Joint_Reset_Register);
-                       ni_set_bits(dev,Interrupt_A_Enable_Register,G0_TC_Interrupt_Enable,  0);
-                       ni_set_bits(dev,Interrupt_A_Enable_Register,G0_Gate_Interrupt_Enable,0);
-                       temp_ack_reg |= G0_Gate_Error_Confirm;
-                       temp_ack_reg |= G0_TC_Error_Confirm;
-                       temp_ack_reg |= G0_TC_Interrupt_Ack;
-                       temp_ack_reg |= G0_Gate_Interrupt_Ack;
-                       win_out(temp_ack_reg,Interrupt_A_Ack_Register);
-               
-                       //problem...this interferes with the other ctr...
-                       devpriv->an_trig_etc_reg |= GPFO_0_Output_Enable;
-                       win_out(devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
-                       break;
-               case 1:
-                       win_out(G1_Reset,Joint_Reset_Register);
-                       ni_set_bits(dev,Interrupt_B_Enable_Register,G1_TC_Interrupt_Enable,  0);
-                       ni_set_bits(dev,Interrupt_B_Enable_Register,G0_Gate_Interrupt_Enable,0);
-                       temp_ack_reg |= G1_Gate_Error_Confirm;
-                       temp_ack_reg |= G1_TC_Error_Confirm;
-                       temp_ack_reg |= G1_TC_Interrupt_Ack;
-                       temp_ack_reg |= G1_Gate_Interrupt_Ack;
-                       win_out(temp_ack_reg,Interrupt_B_Ack_Register);
-               
-                       devpriv->an_trig_etc_reg |= GPFO_1_Output_Enable;
-                       win_out(devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
-                       break;
-       };
-       
-       devpriv->gpct_mode[chan] = 0;
-       devpriv->gpct_input_select[chan] = 0;
-       devpriv->gpct_command[chan] = 0;
-       
-       devpriv->gpct_command[chan] |= G_Synchronized_Gate;
-       
-       win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
-       win_out( devpriv->gpct_input_select[chan],G_Input_Select_Register(chan));
-       win_out( 0,G_Autoincrement_Register(chan));
-               
-       //printk("exit GPCT_Reset\n");
+static inline unsigned num_configurable_rtsi_channels(comedi_device *dev)
+{
+       if(boardtype.reg_type & ni_reg_m_series_mask) return 8;
+       else return 7;
 }
 
-static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+static int ni_mseries_set_pll_master_clock(comedi_device *dev, unsigned source, unsigned period_ns)
 {
-       int retval=0;
-       //printk("data[0] is 0x%08x, data[1] is 0x%08x\n",data[0],data[1]);
-       switch(data[0]){
-       case GPCT_RESET:
-               if(insn->n!=1)return -EINVAL;
-               GPCT_Reset(dev,insn->chanspec);
-               break;
-       case GPCT_SET_SOURCE:
-               if(insn->n!=2)return -EINVAL;
-               retval=GPCT_Set_Source(dev,insn->chanspec,data[1]);
-               break;
-       case GPCT_SET_GATE:
-               if(insn->n!=2)return -EINVAL;
-               retval=GPCT_Set_Gate(dev,insn->chanspec,data[1]);
-               break;
-       case GPCT_SET_DIRECTION:
-               if(insn->n!=2) return -EINVAL;
-               retval=GPCT_Set_Direction(dev,insn->chanspec,data[1]);
-               break;
-       case GPCT_GET_INT_CLK_FRQ:
-               if(insn->n!=2) return -EINVAL;
-               //There are actually 2 internal clocks on the STC, we always
-               //use the fast 20MHz one at this time.  Tim  Ousley 5/1/01
-               //NOTE: This is not the final interface, ideally the user
-               //will never need to know the int. clk. freq.
-               data[1]=50;//50ns = 20MHz = internal timebase of STC
-               break;
-       case GPCT_SET_OPERATION:
-               //TIM 5/1/01 if((insn->n<2)||(insn->n>3))return -EINVAL;
-               switch(data[1]){
-                       case GPCT_SIMPLE_EVENT:
-                               GPCT_Event_Counting(dev,insn->chanspec);
-                               break;
-                       case GPCT_SINGLE_PERIOD:
-                               GPCT_Period_Meas(dev,insn->chanspec);
-                               break;
-                       case GPCT_SINGLE_PW:
-                               GPCT_Pulse_Width_Meas(dev,insn->chanspec);
-                               break;
-                       case GPCT_SINGLE_PULSE_OUT:
-                               GPCT_Gen_Single_Pulse(dev,insn->chanspec,data[2]);
-                               break;
-                       case GPCT_CONT_PULSE_OUT:
-                               GPCT_Gen_Cont_Pulse(dev,insn->chanspec,data[2]);
-                               break;
-                       default:
-                               printk("unsupported GPCT operation!\n");
-                               return -EINVAL;
-               }
-               break;
-       case GPCT_ARM:
-               if(insn->n!=1)return -EINVAL;
-               retval=GPCT_Arm(dev,insn->chanspec);
+       static const unsigned min_period_ns = 50;
+       static const unsigned max_period_ns = 1000;
+       static const unsigned timeout = 1000;
+       unsigned pll_control_bits;
+       unsigned freq_divider;
+       unsigned freq_multiplier;
+       unsigned i;
+       int retval;
+       if(source == NI_MIO_PLL_PXI10_CLOCK) period_ns = 100;
+       // these limits are somewhat arbitrary, but NI advertises 1 to 20MHz range so we'll use that
+       if(period_ns < min_period_ns || period_ns > max_period_ns)
+       {
+               rt_printk("%s: you must specify an input clock frequency between %i and %i nanosec "
+                       "for the phased-lock loop.\n", __FUNCTION__, min_period_ns, max_period_ns);
+               return -EINVAL;
+       }
+       devpriv->rtsi_trig_direction_reg &= ~Use_RTSI_Clock_Bit;
+       devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+       pll_control_bits = MSeries_PLL_Enable_Bit | MSeries_PLL_VCO_Mode_75_150MHz_Bits;
+       devpriv->clock_and_fout2 |= MSeries_Timebase1_Select_Bit | MSeries_Timebase3_Select_Bit;
+       devpriv->clock_and_fout2 &= ~MSeries_PLL_In_Source_Select_Mask;
+       switch(source)
+       {
+       case NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK:
+               devpriv->clock_and_fout2 |= MSeries_PLL_In_Source_Select_Star_Trigger_Bits;
+               retval = ni_mseries_get_pll_parameters(period_ns, &freq_divider,
+                       &freq_multiplier, &devpriv->clock_ns);
+               if(retval < 0) return retval;
                break;
-       case GPCT_DISARM:
-               if(insn->n!=1)return -EINVAL;
-               retval=GPCT_Disarm(dev,insn->chanspec);
+       case NI_MIO_PLL_PXI10_CLOCK:
+               /* pxi clock is 10MHz */
+               devpriv->clock_and_fout2 |= MSeries_PLL_In_Source_Select_PXI_Clock10;
+               retval = ni_mseries_get_pll_parameters(period_ns, &freq_divider,
+                       &freq_multiplier, &devpriv->clock_ns);
+               if(retval < 0) return retval;
                break;
        default:
-               return -EINVAL;
+               {
+                       unsigned rtsi_channel;
+                       static const unsigned max_rtsi_channel = 7;
+                       for(rtsi_channel = 0; rtsi_channel <= max_rtsi_channel; ++rtsi_channel)
+                       {
+                               if(source == NI_MIO_PLL_RTSI_CLOCK(rtsi_channel))
+                               {
+                                       devpriv->clock_and_fout2 |= MSeries_PLL_In_Source_Select_RTSI_Bits(rtsi_channel);
+                                       break;
+                               }
+                       }
+                       if(rtsi_channel > max_rtsi_channel) return -EINVAL;
+                       retval = ni_mseries_get_pll_parameters(period_ns, &freq_divider,
+                               &freq_multiplier, &devpriv->clock_ns);
+                       if(retval < 0) return retval;
+               }
+               break;
        }
-
-       //catch any errors from return values
-       if(retval==0){
-               return insn->n;
-       }else{
-               if(data[0]!=GPCT_ARM){ 
-                       printk("error: retval was %d\n",retval);
-                       printk("data[0] is 0x%08x, data[1] is 0x%08x\n",data[0],data[1]);
+       ni_writew(devpriv->clock_and_fout2, M_Offset_Clock_and_Fout2);
+       pll_control_bits |= MSeries_PLL_Divisor_Bits(freq_divider) | MSeries_PLL_Multiplier_Bits(freq_multiplier);
+//     rt_printk("using divider=%i, multiplier=%i for PLL.  pll_control_bits = 0x%x\n", freq_divider, freq_multiplier, pll_control_bits);
+//     rt_printk("clock_ns=%d\n", devpriv->clock_ns);
+       ni_writew(pll_control_bits, M_Offset_PLL_Control);
+       devpriv->clock_source = source;
+       /* it seems to typically take a few hundred microseconds for PLL to lock */
+       for(i = 0; i < timeout; ++i)
+       {
+               if(ni_readw(M_Offset_PLL_Status) & MSeries_PLL_Locked_Bit)
+               {
+                       break;
                }
-
-               return retval;
+               udelay(1);
+       }
+       if(i == timeout)
+       {
+               rt_printk("%s: timed out waiting for PLL to lock to reference clock source %i with period %i ns.\n",
+                       __FUNCTION__, source, period_ns);
+               return -ETIMEDOUT;
        }
+       return 3;
 }
 
-static int ni_gpct_insn_read(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data) {
-
-       int chan=insn->chanspec;
-       int cur_op = devpriv->gpct_cur_operation[chan];
-
-       //printk("in ni_gpct_insn_read, n=%d, data[0]=%d\n",insn->chanspec,data[0]);
-       if(insn->n!=1)return -EINVAL;
-               
-       data[0] = GPCT_G_Watch(dev,insn->chanspec);
-               
-       /* for certain modes (period and pulse width measurment), the value
-       in the counter is not valid until the counter stops.  If the value is 
-       invalid, return a 0 */
-       if((cur_op == GPCT_SINGLE_PERIOD) || (cur_op == GPCT_SINGLE_PW)){
-               /* is the counter still running? */
-               if(win_in(G_Status_Register) & (chan?G1_Counting_St:G0_Counting_St))
-                       data[0]=0;
+static int ni_set_master_clock(comedi_device *dev, unsigned source, unsigned period_ns)
+{
+       if(source == NI_MIO_INTERNAL_CLOCK)
+       {
+               devpriv->rtsi_trig_direction_reg &= ~Use_RTSI_Clock_Bit;
+               devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+               devpriv->clock_ns = 50;
+               if(boardtype.reg_type & ni_reg_m_series_mask)
+               {
+                       devpriv->clock_and_fout2 &= ~(MSeries_Timebase1_Select_Bit | MSeries_Timebase3_Select_Bit);
+                       ni_writew(devpriv->clock_and_fout2, M_Offset_Clock_and_Fout2);
+                       ni_writew(0, M_Offset_PLL_Control);
+               }
+               devpriv->clock_source = source;
+       }else
+       {
+               if(boardtype.reg_type & ni_reg_m_series_mask)
+               {
+                       return ni_mseries_set_pll_master_clock(dev, source, period_ns);
+               }else
+               {
+                       if(source == NI_MIO_RTSI_CLOCK)
+                       {
+                               devpriv->rtsi_trig_direction_reg |= Use_RTSI_Clock_Bit;
+                               devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+                               if(devpriv->clock_ns == 0)
+                               {
+                                       rt_printk("%s: we don't handle an unspecified clock period correctly yet, returning error.\n",
+                                               __FUNCTION__);
+                                       return -EINVAL;
+                               }else
+                               {
+                                       devpriv->clock_ns = period_ns;
+                               }
+                               devpriv->clock_source = source;
+                       }else
+                               return -EINVAL;
+               }
        }
-       return 1;
+       return 3;
 }
 
-static int ni_gpct_insn_write(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data) {
-
-       //printk("in ni_gpct_insn_write");
-       if(insn->n!=1)return -EINVAL;
-       GPCT_Load_Using_A(dev,insn->chanspec,data[0]);
-       return 1;
+static int ni_valid_rtsi_output_source(comedi_device *dev, unsigned chan, unsigned source)
+{
+       if(chan >= num_configurable_rtsi_channels(dev))
+       {
+               if(chan == old_RTSI_clock_channel)
+               {
+                       if(source == NI_RTSI_OUTPUT_RTSI_OSC) return 1;
+                       else
+                       {
+                               rt_printk("%s: invalid source for channel=%i, channel %i is always the RTSI clock for pre-m-series boards.\n",
+                                       __FUNCTION__, chan, old_RTSI_clock_channel);
+                               return 0;
+                       }
+               }
+               return 0;
+       }
+       switch(source)
+       {
+       case NI_RTSI_OUTPUT_ADR_START1:
+       case NI_RTSI_OUTPUT_ADR_START2:
+       case NI_RTSI_OUTPUT_SCLKG:
+       case NI_RTSI_OUTPUT_DACUPDN:
+       case NI_RTSI_OUTPUT_DA_START1:
+       case NI_RTSI_OUTPUT_G_SRC0:
+       case NI_RTSI_OUTPUT_G_GATE0:
+       case NI_RTSI_OUTPUT_RGOUT0:
+       case NI_RTSI_OUTPUT_RTSI_BRD_0:
+               return 1;
+               break;
+       case NI_RTSI_OUTPUT_RTSI_OSC:
+               if(boardtype.reg_type & ni_reg_m_series_mask)
+                       return 1;
+               else return 0;
+               break;
+       default:
+               return 0;
+               break;
+       }
 }
 
-
-/*
- *
- *  Programmable Function Inputs
- *
- */
-
-static int ni_pfi_insn_bits(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+static int ni_set_rtsi_routing(comedi_device *dev, unsigned chan, unsigned source)
 {
-       if(insn->n!=2)return -EINVAL;
-
-       data[1] = 0;
-
+       if(ni_valid_rtsi_output_source(dev, chan, source) == 0) return -EINVAL;
+       if(chan < 4)
+       {
+               devpriv->rtsi_trig_a_output_reg &= ~RTSI_Trig_Output_Mask(chan);
+               devpriv->rtsi_trig_a_output_reg |= RTSI_Trig_Output_Bits(chan, source);
+               devpriv->stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
+                       RTSI_Trig_A_Output_Register);
+       }else if(chan < 8)
+       {
+               devpriv->rtsi_trig_b_output_reg &= ~RTSI_Trig_Output_Mask(chan);
+               devpriv->rtsi_trig_b_output_reg |= RTSI_Trig_Output_Bits(chan, source);
+               devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
+                       RTSI_Trig_B_Output_Register);
+       }
        return 2;
 }
 
-static int ni_pfi_insn_config(comedi_device *dev,comedi_subdevice *s,
-       comedi_insn *insn,lsampl_t *data)
+static unsigned ni_get_rtsi_routing(comedi_device *dev, unsigned chan)
 {
-       unsigned int chan;
-
-       if(insn->n!=1)return -EINVAL;
-
-       chan = CR_CHAN(insn->chanspec);
-       if(chan>10)return -EINVAL;
+       if(chan < 4)
+       {
+               return RTSI_Trig_Output_Source(chan, devpriv->rtsi_trig_a_output_reg);
+       }else if(chan < num_configurable_rtsi_channels(dev))
+       {
+               return RTSI_Trig_Output_Source(chan, devpriv->rtsi_trig_b_output_reg);
+       }else
+       {
+               if(chan == old_RTSI_clock_channel)
+                       return NI_RTSI_OUTPUT_RTSI_OSC;
+               rt_printk("%s: bug! should never get here?\n", __FUNCTION__);
+               return 0;
+       }
+}
 
+static int ni_rtsi_insn_config(comedi_device *dev,comedi_subdevice *s,
+       comedi_insn *insn,lsampl_t *data)
+{
+       unsigned int chan = CR_CHAN(insn->chanspec);
        switch(data[0]){
-       case COMEDI_OUTPUT:
-               ni_set_bits(dev, IO_Bidirection_Pin_Register, 1<<chan, 1);
+       case INSN_CONFIG_DIO_OUTPUT:
+               if(chan < num_configurable_rtsi_channels(dev))
+               {
+                       devpriv->rtsi_trig_direction_reg |= RTSI_Output_Bit(chan, (boardtype.reg_type & ni_reg_m_series_mask) != 0);
+               }else if(chan == old_RTSI_clock_channel)
+               {
+                       devpriv->rtsi_trig_direction_reg |= Drive_RTSI_Clock_Bit;
+               }
+               devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
                break;
-       case COMEDI_INPUT:
-               ni_set_bits(dev, IO_Bidirection_Pin_Register, 1<<chan, 0);
+       case INSN_CONFIG_DIO_INPUT:
+               if(chan < num_configurable_rtsi_channels(dev))
+               {
+                       devpriv->rtsi_trig_direction_reg &= ~RTSI_Output_Bit(chan, (boardtype.reg_type & ni_reg_m_series_mask) != 0);
+               }else if(chan == old_RTSI_clock_channel)
+               {
+                       devpriv->rtsi_trig_direction_reg &= ~Drive_RTSI_Clock_Bit;
+               }
+               devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+               break;
+       case INSN_CONFIG_DIO_QUERY:
+               if(chan < num_configurable_rtsi_channels(dev))
+               {
+                       data[1] = (devpriv->rtsi_trig_direction_reg & RTSI_Output_Bit(chan, (boardtype.reg_type & ni_reg_m_series_mask) != 0)) ?
+                               INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
+               }else if(chan == old_RTSI_clock_channel)
+               {
+                       data[1] = (devpriv->rtsi_trig_direction_reg & Drive_RTSI_Clock_Bit) ? INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
+               }
+               return 2;
+               break;
+       case INSN_CONFIG_SET_CLOCK_SRC:
+               return ni_set_master_clock(dev, data[1], data[2]);
+               break;
+       case INSN_CONFIG_GET_CLOCK_SRC:
+               data[1] = devpriv->clock_source;
+               data[2] = devpriv->clock_ns;
+               return 3;
+               break;
+       case INSN_CONFIG_SET_ROUTING:
+               return ni_set_rtsi_routing(dev, chan, data[1]);
+               break;
+       case INSN_CONFIG_GET_ROUTING:
+               data[1] = ni_get_rtsi_routing(dev, chan);
+               return 2;
                break;
        default:
                return -EINVAL;
+               break;
        }
-
        return 1;
 }