Most drivers ignore the base channel in insn->chanspec for INSN_BITS
authorIan Abbott <abbotti@mev.co.uk>
Tue, 18 Jan 2011 16:26:27 +0000 (16:26 +0000)
committerIan Abbott <abbotti@mev.co.uk>
Tue, 18 Jan 2011 16:26:27 +0000 (16:26 +0000)
instructions.  If the subdevice has no more than 32 channels, and the
base channel is non-zero, modify the instruction chanspec and data before
passing it to the driver with base channel set to 0, and modify the
returned data.

comedi/comedi_fops.c

index 1218248ef2ee72b6f5f44b2e7c3c101bf622a3a1..b07a34bbd0bf08b878c07acdc6413806f2912c51 100644 (file)
@@ -936,9 +936,29 @@ static int parse_insn(comedi_device * dev, comedi_insn * insn, lsampl_t * data,
                case INSN_BITS:
                        if (insn->n != 2) {
                                ret = -EINVAL;
-                               break;
+                       } else {
+                               /* Most drivers ignore the base channel in
+                                * insn->chanspec.  Deal with it here if
+                                * the subdevice has <= 32 channels. */
+                               unsigned int shift;
+                               lsampl_t orig_mask;
+
+                               orig_mask = data[0];
+                               if (s->n_chan <= 32) {
+                                       shift = CR_CHAN(insn->chanspec);
+                                       if (shift > 0) {
+                                               insn->chanspec = 0;
+                                               data[0] <<= shift;
+                                               data[1] <<= shift;
+                                       }
+                               } else {
+                                       shift = 0;
+                               }
+                               ret = s->insn_bits(dev, s, insn, data);
+                               data[0] = orig_mask;
+                               if (shift > 0)
+                                       data[1] >>= shift;
                        }
-                       ret = s->insn_bits(dev, s, insn, data);
                        break;
                case INSN_CONFIG:
                        ret = check_insn_config_length(insn, data);