diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/ni_mio_common.c')
-rw-r--r-- | drivers/staging/comedi/drivers/ni_mio_common.c | 172 |
1 files changed, 108 insertions, 64 deletions
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 0f97d7b611d7..b2e382888981 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1832,11 +1832,10 @@ static int ni_ai_insn_read(struct comedi_device *dev, unsigned int *data) { struct ni_private *devpriv = dev->private; - unsigned int mask = (s->maxdata + 1) >> 1; + unsigned int mask = s->maxdata; int i, n; unsigned int signbits; unsigned int d; - unsigned long dl; ni_load_channelgain_list(dev, s, 1, &insn->chanspec); @@ -1875,7 +1874,7 @@ static int ni_ai_insn_read(struct comedi_device *dev, return -ETIME; } d += signbits; - data[n] = d; + data[n] = d & 0xffff; } } else if (devpriv->is_6143) { for (n = 0; n < insn->n; n++) { @@ -1887,15 +1886,15 @@ static int ni_ai_insn_read(struct comedi_device *dev, * bit to move a single 16bit stranded sample into * the FIFO. */ - dl = 0; + d = 0; for (i = 0; i < NI_TIMEOUT; i++) { if (ni_readl(dev, NI6143_AI_FIFO_STATUS_REG) & 0x01) { /* Get stranded sample into FIFO */ ni_writel(dev, 0x01, NI6143_AI_FIFO_CTRL_REG); - dl = ni_readl(dev, - NI6143_AI_FIFO_DATA_REG); + d = ni_readl(dev, + NI6143_AI_FIFO_DATA_REG); break; } } @@ -1903,7 +1902,7 @@ static int ni_ai_insn_read(struct comedi_device *dev, dev_err(dev->class_dev, "timeout\n"); return -ETIME; } - data[n] = (((dl >> 16) & 0xFFFF) + signbits) & 0xFFFF; + data[n] = (((d >> 16) & 0xFFFF) + signbits) & 0xFFFF; } } else { for (n = 0; n < insn->n; n++) { @@ -1919,14 +1918,13 @@ static int ni_ai_insn_read(struct comedi_device *dev, return -ETIME; } if (devpriv->is_m_series) { - dl = ni_readl(dev, NI_M_AI_FIFO_DATA_REG); - dl &= mask; - data[n] = dl; + d = ni_readl(dev, NI_M_AI_FIFO_DATA_REG); + d &= mask; + data[n] = d; } else { d = ni_readw(dev, NI_E_AI_FIFO_DATA_REG); - /* subtle: needs to be short addition */ d += signbits; - data[n] = d; + data[n] = d & 0xffff; } } } @@ -2729,66 +2727,36 @@ static int ni_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int ni_ao_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - const struct ni_board_struct *board = dev->board_ptr; - struct ni_private *devpriv = dev->private; - unsigned int nbytes; - - switch (data[0]) { - case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE: - switch (data[1]) { - case COMEDI_OUTPUT: - nbytes = comedi_samples_to_bytes(s, - board->ao_fifo_depth); - data[2] = 1 + nbytes; - if (devpriv->mite) - data[2] += devpriv->mite->fifo_size; - break; - case COMEDI_INPUT: - data[2] = 0; - break; - default: - return -EINVAL; - } - return 0; - default: - break; - } - - return -EINVAL; -} - -static int ni_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int trig_num) +/* + * Arms the AO device in preparation for a trigger event. + * This function also allocates and prepares a DMA channel (or FIFO if DMA is + * not used). As a part of this preparation, this function preloads the DAC + * registers with the first values of the output stream. This ensures that the + * first clock cycle after the trigger can be used for output. + * + * Note that this function _must_ happen after a user has written data to the + * output buffers via either mmap or write(fileno,...). + */ +static int ni_ao_arm(struct comedi_device *dev, + struct comedi_subdevice *s) { struct ni_private *devpriv = dev->private; - struct comedi_cmd *cmd = &s->async->cmd; int ret; int interrupt_b_bits; int i; static const int timeout = 1000; /* - * Require trig_num == cmd->start_arg when cmd->start_src == TRIG_INT. - * For backwards compatibility, also allow trig_num == 0 when - * cmd->start_src != TRIG_INT (i.e. when cmd->start_src == TRIG_EXT); - * in that case, the internal trigger is being used as a pre-trigger - * before the external trigger. + * Prevent ao from doing things like trying to allocate the ao dma + * channel multiple times. */ - if (!(trig_num == cmd->start_arg || - (trig_num == 0 && cmd->start_src != TRIG_INT))) + if (!devpriv->ao_needs_arming) { + dev_dbg(dev->class_dev, "%s: device does not need arming!\n", + __func__); return -EINVAL; + } - /* - * Null trig at beginning prevent ao start trigger from executing more - * than once per command (and doing things like trying to allocate the - * ao dma channel multiple times). - */ - s->async->inttrig = NULL; + devpriv->ao_needs_arming = 0; ni_set_bits(dev, NISTC_INTB_ENA_REG, NISTC_INTB_ENA_AO_FIFO | NISTC_INTB_ENA_AO_ERR, 0); @@ -2840,6 +2808,75 @@ static int ni_ao_inttrig(struct comedi_device *dev, devpriv->ao_cmd1, NISTC_AO_CMD1_REG); + return 0; +} + +static int ni_ao_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + const struct ni_board_struct *board = dev->board_ptr; + struct ni_private *devpriv = dev->private; + unsigned int nbytes; + + switch (data[0]) { + case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE: + switch (data[1]) { + case COMEDI_OUTPUT: + nbytes = comedi_samples_to_bytes(s, + board->ao_fifo_depth); + data[2] = 1 + nbytes; + if (devpriv->mite) + data[2] += devpriv->mite->fifo_size; + break; + case COMEDI_INPUT: + data[2] = 0; + break; + default: + return -EINVAL; + } + return 0; + case INSN_CONFIG_ARM: + return ni_ao_arm(dev, s); + default: + break; + } + + return -EINVAL; +} + +static int ni_ao_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) +{ + struct ni_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; + + /* + * Require trig_num == cmd->start_arg when cmd->start_src == TRIG_INT. + * For backwards compatibility, also allow trig_num == 0 when + * cmd->start_src != TRIG_INT (i.e. when cmd->start_src == TRIG_EXT); + * in that case, the internal trigger is being used as a pre-trigger + * before the external trigger. + */ + if (!(trig_num == cmd->start_arg || + (trig_num == 0 && cmd->start_src != TRIG_INT))) + return -EINVAL; + + /* + * Null trig at beginning prevent ao start trigger from executing more + * than once per command. + */ + s->async->inttrig = NULL; + + if (devpriv->ao_needs_arming) { + /* only arm this device if it still needs arming */ + ret = ni_ao_arm(dev, s); + if (ret) + return ret; + } + ni_stc_writew(dev, NISTC_AO_CMD2_START1_PULSE | devpriv->ao_cmd2, NISTC_AO_CMD2_REG); @@ -3227,10 +3264,17 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) ni_ao_cmd_set_interrupts(dev, s); /* - * arm(ing) and star(ting) happen in ni_ao_inttrig, which _must_ be - * called for ao commands since 1) TRIG_NOW is not supported and 2) DMA - * must be setup and initially written to before arm/start happen. + * arm(ing) must happen later so that DMA can be setup and DACs + * preloaded with the actual output buffer before starting. + * + * start(ing) must happen _after_ arming is completed. Starting can be + * done either via ni_ao_inttrig, or via an external trigger. + * + * **Currently, ni_ao_inttrig will automatically attempt a call to + * ni_ao_arm if the device still needs arming at that point. This + * allows backwards compatibility. */ + devpriv->ao_needs_arming = 1; return 0; } |