configfs: Refactor ConfigFS parsing code
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Sat, 26 May 2018 17:58:19 +0000 (20:58 +0300)
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Fri, 1 Jun 2018 06:47:11 +0000 (09:47 +0300)
Move all attribute parsing to a top-level configfs_parse_uvc() function,
and split control and streaming interface attributes to two separate
helper functions. In addition to making the code more structured, it
will also allow supporting multiple streaming interfaces in a single UVC
function in the future.

The uvc_function_config structure is similarly reorganized in a
hierarchical representation of the configuration.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
configfs.c
configfs.h
uvc-gadget.c

index 3b98f55..38954d5 100644 (file)
@@ -199,12 +199,21 @@ static char *udc_find_video_device(const char *udc, const char *function)
  */
 
 static const struct uvc_function_config g_webcam_config = {
-       .control_interface = 0,
-       .streaming_interface = 1,
-
-       .streaming_interval = 1,
-       .streaming_maxburst = 0,
-       .streaming_maxpacket = 1024,
+       .control = {
+               .intf = {
+                       .bInterfaceNumber = 0,
+               },
+       },
+       .streaming = {
+               .intf = {
+                       .bInterfaceNumber = 1,
+               },
+               .ep = {
+                       .bInterval = 1,
+                       .bMaxBurst = 0,
+                       .wMaxPacketSize = 1024,
+               },
+       },
 };
 
 static int parse_legacy_g_webcam(const char *udc,
@@ -269,16 +278,74 @@ void configfs_free_uvc_function(struct uvc_function_config *fc)
        free(fc);
 }
 
-static int configfs_parse_interfaces(const char *fpath,
-                                    struct uvc_function_config *fc)
+#define configfs_parse_child(parent, child, cfg, parse)                        \
+({                                                                     \
+       char *__path;                                                   \
+       int __ret;                                                      \
+                                                                       \
+       __path = path_join((parent), (child));                          \
+       if (__path) {                                                   \
+               __ret = parse(__path, (cfg));                           \
+               free(__path);                                           \
+       } else {                                                        \
+               __ret = -ENOMEM;                                        \
+       }                                                               \
+                                                                       \
+       __ret;                                                          \
+})
+
+static int configfs_parse_interface(const char *path,
+                                   struct uvc_function_config_interface *cfg)
 {
        int ret;
 
-       ret = attribute_read_uint(fpath, "control/bInterfaceNumber",
-                                 &fc->control_interface);
+       ret = attribute_read_uint(path, "bInterfaceNumber",
+                                 &cfg->bInterfaceNumber);
+
+       return ret;
+}
+
+static int configfs_parse_control(const char *path,
+                                 struct uvc_function_config_control *cfg)
+{
+       int ret;
+
+       ret = configfs_parse_interface(path, &cfg->intf);
+
+       return ret;
+}
+
+static int configfs_parse_streaming(const char *path,
+                                   struct uvc_function_config_streaming *cfg)
+{
+       int ret;
+
+       ret = configfs_parse_interface(path, &cfg->intf);
+
+       return ret;
+}
+
+static int configfs_parse_uvc(const char *fpath,
+                             struct uvc_function_config *fc)
+{
+       int ret = 0;
 
-       ret = ret ? : attribute_read_uint(fpath, "streaming/bInterfaceNumber",
-                                         &fc->streaming_interface);
+       ret = ret ? : configfs_parse_child(fpath, "control", &fc->control,
+                                          configfs_parse_control);
+       ret = ret ? : configfs_parse_child(fpath, "streaming", &fc->streaming,
+                                          configfs_parse_streaming);
+
+       /*
+        * These parameters should be part of the streaming interface in
+        * ConfigFS, but for legacy reasons they are located directly in the
+        * function directory.
+        */
+       ret = ret ? : attribute_read_uint(fpath, "streaming_interval",
+                                         &fc->streaming.ep.bInterval);
+       ret = ret ? : attribute_read_uint(fpath, "streaming_maxburst",
+                                         &fc->streaming.ep.bMaxBurst);
+       ret = ret ? : attribute_read_uint(fpath, "streaming_maxpacket",
+                                         &fc->streaming.ep.wMaxPacketSize);
 
        return ret;
 }
@@ -337,21 +404,14 @@ struct uvc_function_config *configfs_parse_uvc_function(const char *function)
 
        fc->udc = attribute_read_str(fpath, "../../UDC");
        fc->video = udc_find_video_device(fc->udc, function);
-       if (!fc->video)
+       if (!fc->video) {
                ret = -ENODEV;
+               goto done;
+       }
 
-       /* Identify interface numbers. */
-       ret = ret ? : configfs_parse_interfaces(fpath, fc);
-
-       ret = ret ? : attribute_read_uint(fpath, "streaming_interval",
-                                         &fc->streaming_interval);
-
-       ret = ret ? : attribute_read_uint(fpath, "streaming_maxburst",
-                                         &fc->streaming_maxburst);
-
-       ret = ret ? : attribute_read_uint(fpath, "streaming_maxpacket",
-                                         &fc->streaming_maxpacket);
+       ret = configfs_parse_uvc(fpath, fc);
 
+done:
        if (ret) {
                configfs_free_uvc_function(fc);
                fc = NULL;
index b5c7480..9f7f377 100644 (file)
 #define __CONFIGFS_H__
 
 /*
+ * struct uvc_function_config_endpoint - Endpoint parameters
+ * @bInterval: Transfer interval (interrupt and isochronous only)
+ * @bMaxBurst: Transfer burst size (super-speed only)
+ * @wMaxPacketSize: Maximum packet size (including the multiplier)
+ */
+struct uvc_function_config_endpoint {
+       unsigned int bInterval;
+       unsigned int bMaxBurst;
+       unsigned int wMaxPacketSize;
+};
+
+/*
+ * struct uvc_function_config_interface - Interface parameters
+ * @bInterfaceNumber: Interface number
+ */
+struct uvc_function_config_interface {
+       unsigned int bInterfaceNumber;
+};
+
+/*
+ * struct uvc_function_config_control - Control interface parameters
+ * @intf: Generic interface parameters
+ */
+struct uvc_function_config_control {
+       struct uvc_function_config_interface intf;
+};
+
+/*
+ * struct uvc_function_config_streaming - Streaming interface parameters
+ * @intf: Generic interface parameters
+ * @ep: Endpoint parameters
+ */
+struct uvc_function_config_streaming {
+       struct uvc_function_config_interface intf;
+       struct uvc_function_config_endpoint ep;
+};
+
+/*
  * struct uvc_function_config - UVC function configuration parameters
  * @video: Full path to the video device node
  * @udc: UDC name
- * @control_interface: Control interface number
- * @streaming_interface: Streaming interface number
- * @streaming_interval: Isochronous interval for the streaming endpoint
- * @streaming_maxburts: Isochronous maximum burst for the streaming endpoint
- * @streaming_maxpacket: Isochronous maximum packets for the streaming endpoint
+ * @control: Control interface configuration
+ * @streaming: Streaming interface configuration
  */
 struct uvc_function_config {
        char *video;
        char *udc;
 
-       unsigned int control_interface;
-       unsigned int streaming_interface;
-
-       unsigned int streaming_interval;
-       unsigned int streaming_maxburst;
-       unsigned int streaming_maxpacket;
+       struct uvc_function_config_control control;
+       struct uvc_function_config_streaming streaming;
 };
 
 struct uvc_function_config *configfs_parse_uvc_function(const char *function);
index 96f9996..57dc097 100644 (file)
@@ -414,9 +414,9 @@ uvc_events_process_class(struct uvc_device *dev,
        if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE)
                return;
 
-       if (interface == dev->fc->control_interface)
+       if (interface == dev->fc->control.intf.bInterfaceNumber)
                uvc_events_process_control(dev, ctrl->bRequest, ctrl->wValue >> 8, resp);
-       else if (interface == dev->fc->streaming_interface)
+       else if (interface == dev->fc->streaming.intf.bInterfaceNumber)
                uvc_events_process_streaming(dev, ctrl->bRequest, ctrl->wValue >> 8, resp);
 }