staging: comedi: ni_mio_common: fix ni_ao_insn_write()
authorH Hartley Sweeten <hsweeten@visionengravers.com>
Mon, 14 Jul 2014 19:23:43 +0000 (12:23 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 Jul 2014 20:24:42 +0000 (13:24 -0700)
Comedi (*insn_write) functions are expected to write insn->n values
to the hardware. Fix this function to work like the core expects.

Also, don't rely on the return value of ni_ao_comfig_chanlist() to
determine if the values need converted to two's complement before
writing to the hardware. Use the comedi_range_is_bipolar() and
comedi_offset_munge() helpers to clarify the code.

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/comedi/drivers/ni_mio_common.c

index d937eb8..c08b9b6 100644 (file)
@@ -3079,23 +3079,43 @@ static int ni_ao_insn_read(struct comedi_device *dev,
 
 static int ni_ao_insn_write(struct comedi_device *dev,
                            struct comedi_subdevice *s,
-                           struct comedi_insn *insn, unsigned int *data)
+                           struct comedi_insn *insn,
+                           unsigned int *data)
 {
        struct ni_private *devpriv = dev->private;
        unsigned int chan = CR_CHAN(insn->chanspec);
-       unsigned int invert;
+       unsigned int range = CR_RANGE(insn->chanspec);
+       int reg;
+       int i;
 
-       invert = ni_ao_config_chanlist(dev, s, &insn->chanspec, 1, 0);
+       if (devpriv->is_m_series)
+               reg = M_Offset_DAC_Direct_Data(chan);
+       else
+               reg = (chan) ? DAC1_Direct_Data : DAC0_Direct_Data;
 
-       devpriv->ao[chan] = data[0];
+       ni_ao_config_chanlist(dev, s, &insn->chanspec, 1, 0);
 
-       if (devpriv->is_m_series) {
-               ni_writew(dev, data[0], M_Offset_DAC_Direct_Data(chan));
-       } else
-               ni_writew(dev, data[0] ^ invert,
-                         (chan) ? DAC1_Direct_Data : DAC0_Direct_Data);
+       for (i = 0; i < insn->n; i++) {
+               unsigned int val = data[i];
 
-       return 1;
+               devpriv->ao[chan] = val;
+
+               if (devpriv->is_m_series) {
+                       /* M-series board always use offset binary values */
+                       ni_writew(dev, val, reg);
+               } else {
+                       /*
+                        * Non-M series boards need two's complement values
+                        * for bipolar ranges.
+                        */
+                       if (comedi_range_is_bipolar(s, range))
+                               val = comedi_offset_munge(s, val);
+
+                       ni_writew(dev, val, reg);
+               }
+       }
+
+       return insn->n;
 }
 
 static int ni_ao_insn_write_671x(struct comedi_device *dev,