From 6aab7fee7a24395db1b556a5e5cf30aa2627c2be Mon Sep 17 00:00:00 2001 From: "Spencer E. Olson" Date: Wed, 27 Jan 2016 14:28:28 -0700 Subject: [PATCH] staging: comedi: ni_mio_common: adds finite regeneration to AO output This patch implements for analog output the reinterpretation of stop_arg when stop_src == TRIG_NONE to allow the user to specify the length of the buffer that should be repeated. The intent is to allow a user to have a specific buffer repeated as-is indefinitely. The contents of the DMA buffer can be left static or changed by the user via mmap access to the DMA buffer. If the contents are changed by the user, additional munging is not performed by the driver and only a single call to comedi_mark_buffer_written should be done. Signed-off-by: Spencer E. Olson Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- .../staging/comedi/drivers/ni_mio_common.c | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 8f0fe3a26c73..1a22c79c2817 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1500,7 +1500,8 @@ static void handle_b_interrupt(struct comedi_device *dev, s->async->events |= COMEDI_CB_OVERFLOW; } - if (b_status & NISTC_AO_STATUS1_BC_TC) + if (s->async->cmd.stop_src != TRIG_NONE && + b_status & NISTC_AO_STATUS1_BC_TC) s->async->events |= COMEDI_CB_EOA; #ifndef PCIDMA @@ -2073,6 +2074,37 @@ static unsigned ni_timer_to_ns(const struct comedi_device *dev, int timer) return devpriv->clock_ns * (timer + 1); } +static void ni_cmd_set_mite_transfer(struct mite_dma_descriptor_ring *ring, + struct comedi_subdevice *sdev, + const struct comedi_cmd *cmd, + unsigned int max_count) { +#ifdef PCIDMA + unsigned int nbytes = max_count; + + if (cmd->stop_arg > 0 && cmd->stop_arg < max_count) + nbytes = cmd->stop_arg; + nbytes *= comedi_bytes_per_scan(sdev); + + if (nbytes > sdev->async->prealloc_bufsz) { + if (cmd->stop_arg > 0) + dev_err(sdev->device->class_dev, + "ni_cmd_set_mite_transfer: tried exact data transfer limits greater than buffer size\n"); + + /* + * we can only transfer up to the size of the buffer. In this + * case, the user is expected to continue to write into the + * comedi buffer (already implemented as a ring buffer). + */ + nbytes = sdev->async->prealloc_bufsz; + } + + mite_init_ring_descriptors(ring, sdev, nbytes); +#else + dev_err(sdev->device->class_dev, + "ni_cmd_set_mite_transfer: exact data transfer limits not implemented yet without DMA\n"); +#endif +} + static unsigned ni_min_ai_scan_period_ns(struct comedi_device *dev, unsigned num_channels) { @@ -3062,12 +3094,16 @@ static void ni_ao_cmd_set_counters(struct comedi_device *dev, devpriv->ao_mode2 &= ~NISTC_AO_MODE2_UC_INIT_LOAD_SRC; ni_stc_writew(dev, devpriv->ao_mode2, NISTC_AO_MODE2_REG); + /* + * if a user specifies '0', this automatically assumes the entire 24bit + * address space is available for the (multiple iterations of single + * buffer) MISB. Otherwise, stop_arg specifies the MISB length that + * will be used, regardless of whether we are in continuous mode or not. + * In continuous mode, the output will just iterate indefinitely over + * the MISB. + */ { - /* - * Current behavior is to configure the maximum update count - * possible when continuous output mode is requested. - */ - unsigned int stop_arg = cmd->stop_src == TRIG_COUNT ? + unsigned int stop_arg = cmd->stop_arg > 0 ? (cmd->stop_arg & 0xffffff) : 0xffffff; if (devpriv->is_m_series) { @@ -3311,6 +3347,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) ni_ao_cmd_set_channels(dev, s); ni_ao_cmd_set_stop_conditions(dev, cmd); ni_ao_cmd_set_fifo_mode(dev); + ni_cmd_set_mite_transfer(devpriv->ao_mite_ring, s, cmd, 0x00ffffff); ni_ao_cmd_set_interrupts(dev, s); /* @@ -3381,11 +3418,7 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - if (cmd->stop_src == TRIG_COUNT) - err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); - else /* TRIG_NONE */ - err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); + err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); if (err) return 3; @@ -5240,7 +5273,6 @@ static irqreturn_t ni_E_interrupt(int irq, void *d) unsigned long flags; #ifdef PCIDMA struct ni_private *devpriv = dev->private; - struct mite_struct *mite = devpriv->mite; #endif if (!dev->attached) @@ -5252,8 +5284,7 @@ static irqreturn_t ni_E_interrupt(int irq, void *d) a_status = ni_stc_readw(dev, NISTC_AI_STATUS1_REG); b_status = ni_stc_readw(dev, NISTC_AO_STATUS1_REG); #ifdef PCIDMA - if (mite) { - struct ni_private *devpriv = dev->private; + if (devpriv->mite) { unsigned long flags_too; spin_lock_irqsave(&devpriv->mite_channel_lock, flags_too); @@ -5269,7 +5300,7 @@ static irqreturn_t ni_E_interrupt(int irq, void *d) ao_mite_status = mite_get_status(devpriv->ao_mite_chan); if (ao_mite_status & CHSR_LINKC) writel(CHOR_CLRLC, - mite->mite_io_addr + + devpriv->mite->mite_io_addr + MITE_CHOR(devpriv-> ao_mite_chan->channel)); } -- 2.39.5