]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
staging: comedi: add new device-global config interface
authorSpencer E. Olson <olsonse@umich.edu>
Wed, 3 Oct 2018 20:56:02 +0000 (14:56 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Oct 2018 13:32:38 +0000 (15:32 +0200)
Adds interface for configuring options that are global to all sub-devices.
For now, only options to configure device-globally identified signal routes
have been defined.

Signed-off-by: Spencer E. Olson <olsonse@umich.edu>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/comedi/comedi.h
drivers/staging/comedi/comedi_fops.c
drivers/staging/comedi/comedidev.h
drivers/staging/comedi/drivers.c

index e9ce395836ec7b8b363f5d29b61abcd5a0fab527..e90b1777528403ea43e3d575b17e90c363f5b9e4 100644 (file)
 #define INSN_WRITE             (1 | INSN_MASK_WRITE)
 #define INSN_BITS              (2 | INSN_MASK_READ | INSN_MASK_WRITE)
 #define INSN_CONFIG            (3 | INSN_MASK_READ | INSN_MASK_WRITE)
+#define INSN_DEVICE_CONFIG     (INSN_CONFIG | INSN_MASK_SPECIAL)
 #define INSN_GTOD              (4 | INSN_MASK_READ | INSN_MASK_SPECIAL)
 #define INSN_WAIT              (5 | INSN_MASK_WRITE | INSN_MASK_SPECIAL)
 #define INSN_INTTRIG           (6 | INSN_MASK_WRITE | INSN_MASK_SPECIAL)
@@ -350,6 +351,23 @@ enum configuration_ids {
        INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS = 5005,
 };
 
+/**
+ * enum device_configuration_ids - COMEDI configuration instruction codes global
+ * to an entire device.
+ * @INSN_DEVICE_CONFIG_TEST_ROUTE:     Validate the possibility of a
+ *                                     globally-named route
+ * @INSN_DEVICE_CONFIG_CONNECT_ROUTE:  Connect a globally-named route
+ * @INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:Disconnect a globally-named route
+ * @INSN_DEVICE_CONFIG_GET_ROUTES:     Get a list of all globally-named routes
+ *                                     that are valid for a particular device.
+ */
+enum device_config_route_ids {
+       INSN_DEVICE_CONFIG_TEST_ROUTE = 0,
+       INSN_DEVICE_CONFIG_CONNECT_ROUTE = 1,
+       INSN_DEVICE_CONFIG_DISCONNECT_ROUTE = 2,
+       INSN_DEVICE_CONFIG_GET_ROUTES = 3,
+};
+
 /**
  * enum comedi_digital_trig_op - operations for configuring a digital trigger
  * @COMEDI_DIGITAL_TRIG_DISABLE:       Return digital trigger to its default,
index 548baa7905075b56c6cc3156a740e1dbe9d358eb..c1c6b2b4ab91c5cc67165ec0179c997c887bc10f 100644 (file)
@@ -1234,6 +1234,57 @@ static int check_insn_config_length(struct comedi_insn *insn,
        return -EINVAL;
 }
 
+static int check_insn_device_config_length(struct comedi_insn *insn,
+                                          unsigned int *data)
+{
+       if (insn->n < 1)
+               return -EINVAL;
+
+       switch (data[0]) {
+       case INSN_DEVICE_CONFIG_TEST_ROUTE:
+       case INSN_DEVICE_CONFIG_CONNECT_ROUTE:
+       case INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:
+               if (insn->n == 3)
+                       return 0;
+               break;
+       case INSN_DEVICE_CONFIG_GET_ROUTES:
+               /*
+                * Big enough for config_id and the length of the userland
+                * memory buffer.  Additional length should be in factors of 2
+                * to communicate any returned route pairs (source,destination).
+                */
+               if (insn->n >= 2)
+                       return 0;
+               break;
+       }
+       return -EINVAL;
+}
+
+/**
+ * get_valid_routes() - Calls low-level driver get_valid_routes function to
+ *                     either return a count of valid routes to user, or copy
+ *                     of list of all valid device routes to buffer in
+ *                     userspace.
+ * @dev: comedi device pointer
+ * @data: data from user insn call.  The length of the data must be >= 2.
+ *       data[0] must contain the INSN_DEVICE_CONFIG config_id.
+ *       data[1](input) contains the number of _pairs_ for which memory is
+ *               allotted from the user.  If the user specifies '0', then only
+ *               the number of pairs available is returned.
+ *       data[1](output) returns either the number of pairs available (if none
+ *               where requested) or the number of _pairs_ that are copied back
+ *               to the user.
+ *       data[2::2] returns each (source, destination) pair.
+ *
+ * Return: -EINVAL if low-level driver does not allocate and return routes as
+ *        expected.  Returns 0 otherwise.
+ */
+static int get_valid_routes(struct comedi_device *dev, unsigned int *data)
+{
+       data[1] = dev->get_valid_routes(dev, data[1], data + 2);
+       return 0;
+}
+
 static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
                      unsigned int *data, void *file)
 {
@@ -1297,6 +1348,24 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
                        if (ret >= 0)
                                ret = 1;
                        break;
+               case INSN_DEVICE_CONFIG:
+                       ret = check_insn_device_config_length(insn, data);
+                       if (ret)
+                               break;
+
+                       if (data[0] == INSN_DEVICE_CONFIG_GET_ROUTES) {
+                               /*
+                                * data[1] should be the number of _pairs_ that
+                                * the memory can hold.
+                                */
+                               data[1] = (insn->n - 2) / 2;
+                               ret = get_valid_routes(dev, data);
+                               break;
+                       }
+
+                       /* other global device config instructions. */
+                       ret = dev->insn_device_config(dev, insn, data);
+                       break;
                default:
                        dev_dbg(dev->class_dev, "invalid insn\n");
                        ret = -EINVAL;
index 5775a93917f4d5d035c5460fbca910d8e370481e..a7d569cfca5db6b613e31d54eecb48e08f96413e 100644 (file)
@@ -516,6 +516,15 @@ struct comedi_driver {
  *     called when @use_count changes from 0 to 1.
  * @close: Optional pointer to a function set by the low-level driver to be
  *     called when @use_count changed from 1 to 0.
+ * @insn_device_config: Optional pointer to a handler for all sub-instructions
+ *     except %INSN_DEVICE_CONFIG_GET_ROUTES of the %INSN_DEVICE_CONFIG
+ *     instruction.  If this is not initialized by the low-level driver, a
+ *     default handler will be set during post-configuration.
+ * @get_valid_routes: Optional pointer to a handler for the
+ *     %INSN_DEVICE_CONFIG_GET_ROUTES sub-instruction of the
+ *     %INSN_DEVICE_CONFIG instruction set.  If this is not initialized by the
+ *     low-level driver, a default handler that copies zero routes back to the
+ *     user will be used.
  *
  * This is the main control data structure for a COMEDI device (as far as the
  * COMEDI core is concerned).  There are two groups of COMEDI devices -
@@ -565,6 +574,11 @@ struct comedi_device {
 
        int (*open)(struct comedi_device *dev);
        void (*close)(struct comedi_device *dev);
+       int (*insn_device_config)(struct comedi_device *dev,
+                                 struct comedi_insn *insn, unsigned int *data);
+       unsigned int (*get_valid_routes)(struct comedi_device *dev,
+                                        unsigned int n_pairs,
+                                        unsigned int *pair_data);
 };
 
 /*
index 57dd63d548b7c94e03bbdf615daf1889acfc986a..eefa62f42c0f06d8b84e03379c0499d7b66d8ace 100644 (file)
@@ -211,6 +211,19 @@ static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
        return -EINVAL;
 }
 
+static int insn_device_inval(struct comedi_device *dev,
+                            struct comedi_insn *insn, unsigned int *data)
+{
+       return -EINVAL;
+}
+
+static unsigned int get_zero_valid_routes(struct comedi_device *dev,
+                                         unsigned int n_pairs,
+                                         unsigned int *pair_data)
+{
+       return 0;
+}
+
 int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
               struct comedi_insn *insn, unsigned int *data)
 {
@@ -652,6 +665,12 @@ static int __comedi_device_postconfig(struct comedi_device *dev)
        int ret;
        int i;
 
+       if (!dev->insn_device_config)
+               dev->insn_device_config = insn_device_inval;
+
+       if (!dev->get_valid_routes)
+               dev->get_valid_routes = get_zero_valid_routes;
+
        for (i = 0; i < dev->n_subdevices; i++) {
                s = &dev->subdevices[i];