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
{
#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
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;
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))
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;
}
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);
}
#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)
}
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)
{
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;
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);
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);
#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,
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;
/* 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);
}
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;
}