staging: comedi: das6402: add basic (*do_cmdtest) for AI async commands
authorH Hartley Sweeten <hsweeten@visionengravers.com>
Thu, 13 Nov 2014 18:41:01 +0000 (11:41 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Nov 2014 23:35:24 +0000 (15:35 -0800)
Currently the async command support in this driver consists of just the
stubbed in functions.

Flesh out the (*do_cmdtest) function for basic support of timed analog
input acquisitions.

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/das6402.c

index f3909f3f755eff5a28d11607c279bf15c090ba94..29270bdfd2a68ebfc9ac70e13f3cabce7a72e8e2 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/interrupt.h>
 
 #include "../comedidev.h"
+#include "comedi_fc.h"
 #include "8253.h"
 
 /*
@@ -207,11 +208,113 @@ static int das6402_ai_cmd(struct comedi_device *dev,
        return -EINVAL;
 }
 
+static int das6402_ai_check_chanlist(struct comedi_device *dev,
+                                    struct comedi_subdevice *s,
+                                    struct comedi_cmd *cmd)
+{
+       unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+       unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+       unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
+       int i;
+
+       for (i = 1; i < cmd->chanlist_len; i++) {
+               unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+               unsigned int range = CR_RANGE(cmd->chanlist[i]);
+               unsigned int aref = CR_AREF(cmd->chanlist[i]);
+
+               if (chan != chan0 + i) {
+                       dev_dbg(dev->class_dev,
+                               "chanlist must be consecutive\n");
+                       return -EINVAL;
+               }
+
+               if (range != range0) {
+                       dev_dbg(dev->class_dev,
+                               "chanlist must have the same range\n");
+                       return -EINVAL;
+               }
+
+               if (aref != aref0) {
+                       dev_dbg(dev->class_dev,
+                               "chanlist must have the same reference\n");
+                       return -EINVAL;
+               }
+
+               if (aref0 == AREF_DIFF && chan > (s->n_chan / 2)) {
+                       dev_dbg(dev->class_dev,
+                               "chanlist differential channel to large\n");
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 static int das6402_ai_cmdtest(struct comedi_device *dev,
                              struct comedi_subdevice *s,
                              struct comedi_cmd *cmd)
 {
-       return -EINVAL;
+       struct das6402_private *devpriv = dev->private;
+       int err = 0;
+       unsigned int arg;
+
+       /* Step 1 : check if triggers are trivially valid */
+
+       err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+       err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
+       err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
+       err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+       err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
+
+       if (err)
+               return 1;
+
+       /* Step 2a : make sure trigger sources are unique */
+
+       err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+       /* Step 2b : and mutually compatible */
+
+       if (err)
+               return 2;
+
+       /* Step 3: check if arguments are trivially valid */
+
+       err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+       err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+       err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
+       err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
+       err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+
+       if (cmd->stop_src == TRIG_COUNT)
+               err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
+       else    /* TRIG_NONE */
+               err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+       if (err)
+               return 3;
+
+       /* step 4: fix up any arguments */
+
+       if (cmd->convert_src == TRIG_TIMER) {
+               arg = cmd->convert_arg;
+               i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
+                                         &devpriv->divider1,
+                                         &devpriv->divider2,
+                                         &arg, cmd->flags);
+               err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
+       }
+
+       if (err)
+               return 4;
+
+       /* Step 5: check channel list if it exists */
+       if (cmd->chanlist && cmd->chanlist_len > 0)
+               err |= das6402_ai_check_chanlist(dev, s, cmd);
+
+       if (err)
+               return 5;
+
+       return 0;
 }
 
 static int das6402_ai_cancel(struct comedi_device *dev,