DMA works for input with buffered counting on e-series now.
authorFrank Mori Hess <fmhess@speakeasy.net>
Tue, 24 Jul 2007 16:15:50 +0000 (16:15 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Tue, 24 Jul 2007 16:15:50 +0000 (16:15 +0000)
comedi/drivers/mite.c
comedi/drivers/mite.h
comedi/drivers/ni_mio_common.c
comedi/drivers/ni_tio.c

index f2276fd8c04229600b4ad1af688b817b08140f91..6da64c8f7ffab5c637110ea90d97a5df571f880a 100644 (file)
@@ -367,7 +367,8 @@ void mite_prep_dma(struct mite_channel *mite_chan,
        {
                /* Doing a combined 32 and 16 bit byteswap gets the 16 bit samples into the fifo in the right order.
                 Tested doing 32 bit memory to 16 bit device transfers to the analog out of a pxi-6281,
-                which has mite version = 1, type = 4*/
+                which has mite version = 1, type = 4.  This also works for dma reads from the counters
+                on e-series boards.  */
                chcr |= CHCR_BYTE_SWAP_DEVICE | CHCR_BYTE_SWAP_MEMORY;
        }
        if(mite_chan->dir == COMEDI_INPUT){
index 0569f02821b745ce51cd5bf1b55bbf4b62597a2c..df9ff1c7f4d86fb907d2d056ae6afcb4e11c1d73 100644 (file)
@@ -427,5 +427,12 @@ static inline void mite_dma_reset(struct mite_channel *mite_chan)
        writel(CHOR_DMARESET | CHOR_FRESET, mite_chan->mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
 };
 
+static inline unsigned mite_get_status(struct mite_channel *mite_chan)
+{
+       struct mite_struct *mite = mite_chan->mite;
+
+       return readl(mite->mite_io_addr + MITE_CHSR(mite_chan->channel));
+}
+
 #endif
 
index f7434fb67cc804d3355d1f167a58b0fc363aea5f..de9c653f0d7d1b13e0c66969ad994ca6352a5080 100644 (file)
@@ -284,8 +284,8 @@ 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);
-static void ack_a_interrupt(comedi_device *dev, unsigned short a_status);
-static void ack_b_interrupt(comedi_device *dev, unsigned short b_status);
+static void ack_a_interrupt(comedi_device *dev, unsigned short a_status, unsigned short g_status);
+static void ack_b_interrupt(comedi_device *dev, unsigned short b_status, unsigned short g_status);
 
 enum aimodes
 {
@@ -505,6 +505,36 @@ void ni_release_gpct_mite_channel(comedi_device *dev, unsigned gpct_index)
 #endif // PCIDMA
 }
 
+// e-series boards use the second irq signals to generate dma requests for their counters
+static void ni_e_series_enable_second_irq(comedi_device *dev, unsigned gpct_index, short enable)
+{
+       if(boardtype.reg_type & ni_reg_m_series_mask) return;
+       switch(gpct_index)
+       {
+       case 0:
+               if(enable)
+               {
+                       devpriv->stc_writew(dev, G0_Gate_Second_Irq_Enable, Second_IRQ_A_Enable_Register);
+               }else
+               {
+                       devpriv->stc_writew(dev, 0, Second_IRQ_A_Enable_Register);
+               }
+               break;
+       case 1:
+               if(enable)
+               {
+                       devpriv->stc_writew(dev, G1_Gate_Second_Irq_Enable, Second_IRQ_B_Enable_Register);
+               }else
+               {
+                       devpriv->stc_writew(dev, 0, Second_IRQ_B_Enable_Register);
+               }
+               break;
+       default:
+               BUG();
+               break;
+       }
+}
+
 static void ni_clear_ai_fifo(comedi_device *dev){
        if(boardtype.reg_type == ni_reg_6143){
                // Flush the 6143 data FIFO
@@ -628,6 +658,7 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG)
        unsigned short b_status;
        unsigned int ai_mite_status = 0;
        unsigned int ao_mite_status = 0;
+       unsigned g_status;
        unsigned long flags;
        struct mite_struct *mite = devpriv->mite;
 
@@ -649,8 +680,9 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG)
                        ao_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->ao_mite_chan->channel));
                comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags_too);
        }
-       ack_a_interrupt(dev, a_status);
-       ack_b_interrupt(dev, b_status);
+       g_status = devpriv->stc_readw(dev, G_Status_Register);
+       ack_a_interrupt(dev, a_status, g_status);
+       ack_b_interrupt(dev, b_status, g_status);
        if((a_status & Interrupt_A_St) || (ai_mite_status & CHSR_INT))
                handle_a_interrupt(dev, a_status, ai_mite_status);
        if((b_status & Interrupt_B_St) || (ao_mite_status & CHSR_INT))
@@ -826,7 +858,33 @@ static void handle_gpct_interrupt(comedi_device *dev, unsigned short counter_ind
                ni_event(dev, s, s->async->events);
 }
 
-static void ack_a_interrupt(comedi_device *dev, unsigned short a_status)
+       /* During buffered input counter operation for e-series, the gate interrupt is acked
+       automatically by the dma controller, due to the Gi_Read/Write_Acknowledges_IRQ bits
+       in the input select register.  */
+int should_ack_gate(comedi_device *dev, unsigned counter_index)
+{
+       unsigned long flags;
+       int retval = 0;
+
+       if(boardtype.reg_type & ni_reg_m_series_mask) return 1;
+
+       comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+       {
+               struct mite_channel *mite_chan = devpriv->counter_dev->counters[counter_index].mite_chan;
+
+               if(mite_chan == NULL ||
+                       mite_chan->dir != COMEDI_INPUT ||
+                       (mite_get_status(devpriv->counter_dev->counters[counter_index].mite_chan) & CHSR_DONE))
+               {
+                       retval = 1;
+               }
+       }
+       comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+
+       return retval;
+}
+
+static void ack_a_interrupt(comedi_device *dev, unsigned short a_status, unsigned short g_status)
 {
        unsigned short ack = 0;
 
@@ -853,7 +911,12 @@ static void ack_a_interrupt(comedi_device *dev, unsigned short a_status)
        }
        if(a_status & G0_Gate_Interrupt_St)
        {
-               ack |= G0_Gate_Interrupt_Ack;
+               if(should_ack_gate(dev, 0))
+                       ack |= G0_Gate_Interrupt_Ack;
+       }
+       if(g_status & G0_Gate_Error_St)
+       {
+               ack |= G0_Gate_Error_Confirm;
        }
        if(ack) devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register);
 }
@@ -955,7 +1018,7 @@ static void handle_a_interrupt(comedi_device *dev, unsigned short status,
 #endif
 }
 
-static void ack_b_interrupt(comedi_device *dev, unsigned short b_status)
+static void ack_b_interrupt(comedi_device *dev, unsigned short b_status, unsigned short g_status)
 {
        unsigned short ack = 0;
        if(b_status & AO_BC_TC_St)
@@ -988,7 +1051,12 @@ static void ack_b_interrupt(comedi_device *dev, unsigned short b_status)
        }
        if(b_status & G1_Gate_Interrupt_St)
        {
-               ack |= G1_Gate_Interrupt_Ack;
+               if(should_ack_gate(dev, 1))
+                       ack |= G1_Gate_Interrupt_Ack;
+       }
+       if(g_status & G1_Gate_Error_St)
+       {
+               ack |= G1_Gate_Error_Confirm;
        }
        if(b_status & G1_TC_St)
        {
@@ -4424,6 +4492,46 @@ static inline unsigned Gi_Gate_Interrupt_Ack_Bit(unsigned counter_index)
        return bit;
 }
 
+static inline unsigned Gi_Gate_Error_Confirm_Bit(unsigned counter_index)
+{
+       unsigned bit;
+
+       switch(counter_index)
+       {
+       case 0:
+               bit = G0_Gate_Error_Confirm;
+               break;
+       case 1:
+               bit = G1_Gate_Error_Confirm;
+               break;
+       default:
+               BUG();
+               return 0;
+               break;
+       }
+       return bit;
+}
+
+static inline unsigned Gi_TC_Error_Confirm_Bit(unsigned counter_index)
+{
+       unsigned bit;
+
+       switch(counter_index)
+       {
+       case 0:
+               bit = G0_TC_Error_Confirm;
+               break;
+       case 1:
+               bit = G1_TC_Error_Confirm;
+               break;
+       default:
+               BUG();
+               return 0;
+               break;
+       }
+       return bit;
+}
+
 static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s)
 {
        int retval;
@@ -4438,13 +4546,16 @@ static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s)
                comedi_error(dev, "no dma channel available for use by counter");
                return retval;
        }
+       devpriv->stc_writew(dev, Gi_Gate_Interrupt_Ack_Bit(counter->counter_index) |
+               Gi_Gate_Error_Confirm_Bit(counter->counter_index) |
+               Gi_TC_Error_Confirm_Bit(counter->counter_index),
+               Gi_Interrupt_Ack_Register(counter->counter_index));
        if(cmd->flags & TRIG_WAKE_EOS)
        {
-               devpriv->stc_writew(dev, Gi_Gate_Interrupt_Ack_Bit(counter->counter_index),
-                       Gi_Interrupt_Ack_Register(counter->counter_index));
                ni_set_bits(dev, Gi_Interrupt_Enable_Register(counter->counter_index),
                        Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 1);
        }
+       ni_e_series_enable_second_irq(dev, counter->counter_index, 1);
 
        comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
        retval = ni_tio_cmd(counter, s->async);
@@ -4471,6 +4582,8 @@ static int ni_gpct_cancel(comedi_device *dev, comedi_subdevice *s)
        comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
        retval = ni_tio_cancel(counter);
        comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+
+       ni_e_series_enable_second_irq(dev, counter->counter_index, 0);
        ni_set_bits(dev, Gi_Interrupt_Enable_Register(counter->counter_index),
                Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 0);
        ni_release_gpct_mite_channel(dev, counter->counter_index);
index 871fba87ba1c321a87084294118ef45b213462c2..4da555e890e1a6a7697128f87ead3195fdf7f3b8 100644 (file)
@@ -597,6 +597,8 @@ static inline unsigned NI_M_Series_PFI_Gate_Select(unsigned n)
 #define Gi_Gate_Select_Shift 7
 enum Gi_Input_Select_Bits
 {
+       Gi_Read_Acknowledges_Irq = 0x1, // e-series only
+       Gi_Write_Acknowledges_Irq = 0x2,        // e-series only
        Gi_Source_Select_Mask = 0x7c,
        Gi_Gate_Select_Mask = 0x1f << Gi_Gate_Select_Shift,
        Gi_Gate_Select_Load_Source_Bit = 0x1000,
@@ -2124,6 +2126,60 @@ int ni_tio_winsn(struct ni_gpct *counter,
        return 0;
 }
 
+static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, short read_not_write)
+{
+       struct ni_gpct_device *counter_dev = counter->counter_dev;
+
+       switch(counter_dev->variant)
+       {
+       case ni_gpct_variant_e_series:
+               {
+                       const unsigned input_select_reg = NITIO_Gi_Input_Select_Reg(counter->counter_index);
+                       if(enable)
+                       {
+                               if(read_not_write)
+                               {
+                                       counter_dev->regs[input_select_reg] |= Gi_Read_Acknowledges_Irq;
+                                       counter_dev->regs[input_select_reg] &= ~Gi_Write_Acknowledges_Irq;
+                               }else
+                               {
+                                       counter_dev->regs[input_select_reg] &= ~Gi_Read_Acknowledges_Irq;
+                                       counter_dev->regs[input_select_reg] |= Gi_Write_Acknowledges_Irq;
+                               }
+                       }else
+                       {
+                               counter_dev->regs[input_select_reg] &= ~(Gi_Read_Acknowledges_Irq | Gi_Write_Acknowledges_Irq);
+                       }
+                       counter_dev->write_register(counter, counter_dev->regs[input_select_reg], input_select_reg);
+               }
+               break;
+       case ni_gpct_variant_m_series:
+       case ni_gpct_variant_660x:
+               {
+                       const unsigned gi_dma_config_reg = NITIO_Gi_DMA_Config_Reg(counter->counter_index);
+
+                       if(enable)
+                       {
+                               counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Enable_Bit;
+                               counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Int_Bit;
+                       }else
+                       {
+                               counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Enable_Bit;
+                               counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Int_Bit;
+                       }
+                       if(read_not_write)
+                       {
+                               counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Write_Bit;
+                       }else
+                       {
+                               counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Write_Bit;
+                       }
+                       counter_dev->write_register(counter, counter_dev->regs[gi_dma_config_reg], gi_dma_config_reg);
+               }
+               break;
+       }
+}
+
 static int ni_tio_input_cmd(struct ni_gpct *counter, comedi_async *async)
 {
        struct ni_gpct_device *counter_dev = counter->counter_dev;
@@ -2133,40 +2189,34 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, comedi_async *async)
        /* write alloc the entire buffer */
        comedi_buf_write_alloc(async, async->prealloc_bufsz);
        counter->mite_chan->dir = COMEDI_INPUT;
-       mite_prep_dma(counter->mite_chan, 32, 32);
-       counter_dev->regs[command_reg] &= ~Gi_Save_Trace_Bit;
-       counter_dev->write_register(counter, counter_dev->regs[command_reg], command_reg);
-       if(counter_dev->variant == ni_gpct_variant_m_series ||
-               counter_dev->variant == ni_gpct_variant_660x)
+       switch(counter_dev->variant)
        {
-               const unsigned gi_dma_config_reg = NITIO_Gi_DMA_Config_Reg(counter->counter_index);
-
-               counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Enable_Bit;
-               counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Write_Bit;
-               counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Int_Bit;
-               counter_dev->write_register(counter, counter_dev->regs[gi_dma_config_reg], gi_dma_config_reg);
+       case ni_gpct_variant_m_series:
+       case ni_gpct_variant_660x:
+               mite_prep_dma(counter->mite_chan, 32, 32);
+               break;
+       case ni_gpct_variant_e_series:
+               mite_prep_dma(counter->mite_chan, 16, 32);
+               break;
+       default:
+               BUG();
+               break;
        }
+       counter_dev->regs[command_reg] &= ~Gi_Save_Trace_Bit;
+       counter_dev->write_register(counter, counter_dev->regs[command_reg], command_reg);
+       ni_tio_configure_dma(counter, 1, 1);
        mite_dma_arm(counter->mite_chan);
        return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
 }
 
 static int ni_tio_output_cmd(struct ni_gpct *counter, comedi_async *async)
 {
-       struct ni_gpct_device *counter_dev = counter->counter_dev;
-
        rt_printk("ni_tio: output commands not yet implemented.\n");
        return -ENOTSUPP;
 
        counter->mite_chan->dir = COMEDI_OUTPUT;
        mite_prep_dma(counter->mite_chan, 32, 32);
-       if(counter_dev->variant == ni_gpct_variant_m_series ||
-               counter_dev->variant == ni_gpct_variant_660x)
-       {
-               const unsigned gi_dma_config_reg = NITIO_Gi_DMA_Config_Reg(counter->counter_index);
-
-               counter_dev->regs[gi_dma_config_reg] |= Gi_DMA_Enable_Bit | Gi_DMA_Write_Bit;
-               counter_dev->write_register(counter, counter_dev->regs[gi_dma_config_reg], gi_dma_config_reg);
-       }
+       ni_tio_configure_dma(counter, 1, 0);
        mite_dma_arm(counter->mite_chan);
        return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
 }
@@ -2200,22 +2250,12 @@ int ni_tio_cmdtest(struct ni_gpct *counter)
 
 int ni_tio_cancel(struct ni_gpct *counter)
 {
-       struct ni_gpct_device *counter_dev = counter->counter_dev;
-
        ni_tio_arm(counter, 0, 0);
-       if(counter_dev->variant == ni_gpct_variant_m_series ||
-               counter_dev->variant == ni_gpct_variant_660x)
-       {
-               const unsigned gi_dma_config_reg = NITIO_Gi_DMA_Config_Reg(counter->counter_index);
-
-               counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Enable_Bit;
-               counter_dev->regs[gi_dma_config_reg] &= ~Gi_DMA_Int_Bit;
-               counter_dev->write_register(counter, counter_dev->regs[gi_dma_config_reg], gi_dma_config_reg);
-       }
        if(counter->mite_chan)
        {
                mite_dma_disarm(counter->mite_chan);
        }
+       ni_tio_configure_dma(counter, 0, 0);
        return 0;
 }