V4L/DVB: uvcvideo: Cache control min, max, res and def query results
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Sat, 23 Jan 2010 09:30:20 +0000 (06:30 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 26 Feb 2010 18:11:04 +0000 (15:11 -0300)
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvcvideo.h

index f4e5ba260968c6a2c06c30f487a997f5d0b9a4d6..5ff501390842b4655a4dc79399cb1d76721e816a 100644 (file)
 
 #include "uvcvideo.h"
 
-#define UVC_CTRL_NDATA         2
 #define UVC_CTRL_DATA_CURRENT  0
 #define UVC_CTRL_DATA_BACKUP   1
+#define UVC_CTRL_DATA_MIN      2
+#define UVC_CTRL_DATA_MAX      3
+#define UVC_CTRL_DATA_RES      4
+#define UVC_CTRL_DATA_DEF      5
+#define UVC_CTRL_DATA_LAST     6
 
 /* ------------------------------------------------------------------------
  * Controls
@@ -755,6 +759,49 @@ struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
        return ctrl;
 }
 
+static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
+       struct uvc_control *ctrl)
+{
+       int ret;
+
+       if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
+                                    chain->dev->intfnum, ctrl->info->selector,
+                                    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
+                                    ctrl->info->size);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
+                                    chain->dev->intfnum, ctrl->info->selector,
+                                    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
+                                    ctrl->info->size);
+               if (ret < 0)
+                       return ret;
+       }
+       if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
+                                    chain->dev->intfnum, ctrl->info->selector,
+                                    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
+                                    ctrl->info->size);
+               if (ret < 0)
+                       return ret;
+       }
+       if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
+                                    chain->dev->intfnum, ctrl->info->selector,
+                                    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
+                                    ctrl->info->size);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ctrl->cached = 1;
+       return 0;
+}
+
 int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
        struct v4l2_queryctrl *v4l2_ctrl)
 {
@@ -762,17 +809,12 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
        struct uvc_control_mapping *mapping;
        struct uvc_menu_info *menu;
        unsigned int i;
-       __u8 *data;
        int ret;
 
        ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
        if (ctrl == NULL)
                return -EINVAL;
 
-       data = kmalloc(ctrl->info->size, GFP_KERNEL);
-       if (data == NULL)
-               return -ENOMEM;
-
        memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
        v4l2_ctrl->id = mapping->id;
        v4l2_ctrl->type = mapping->v4l2_type;
@@ -782,14 +824,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
        if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
                v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
-       if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
-               ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
-                                    chain->dev->intfnum, ctrl->info->selector,
-                                    data, ctrl->info->size);
+       if (!ctrl->cached) {
+               ret = uvc_ctrl_populate_cache(chain, ctrl);
                if (ret < 0)
-                       goto out;
-               v4l2_ctrl->default_value =
-                       mapping->get(mapping, UVC_GET_DEF, data);
+                       return ret;
+       }
+
+       if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+               v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
+                               uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
        }
 
        switch (mapping->v4l2_type) {
@@ -806,56 +849,37 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
                        }
                }
 
-               ret = 0;
-               goto out;
+               return 0;
 
        case V4L2_CTRL_TYPE_BOOLEAN:
                v4l2_ctrl->minimum = 0;
                v4l2_ctrl->maximum = 1;
                v4l2_ctrl->step = 1;
-               ret = 0;
-               goto out;
+               return 0;
 
        case V4L2_CTRL_TYPE_BUTTON:
                v4l2_ctrl->minimum = 0;
                v4l2_ctrl->maximum = 0;
                v4l2_ctrl->step = 0;
-               ret = 0;
-               goto out;
+               return 0;
 
        default:
                break;
        }
 
-       if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
-               ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
-                                    chain->dev->intfnum, ctrl->info->selector,
-                                    data, ctrl->info->size);
-               if (ret < 0)
-                       goto out;
-               v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
-       }
-       if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
-               ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
-                                    chain->dev->intfnum, ctrl->info->selector,
-                                    data, ctrl->info->size);
-               if (ret < 0)
-                       goto out;
-               v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
-       }
-       if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
-               ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
-                                    chain->dev->intfnum, ctrl->info->selector,
-                                    data, ctrl->info->size);
-               if (ret < 0)
-                       goto out;
-               v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
-       }
+       if (ctrl->info->flags & UVC_CONTROL_GET_MIN)
+               v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
+                                    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
 
-       ret = 0;
-out:
-       kfree(data);
-       return ret;
+       if (ctrl->info->flags & UVC_CONTROL_GET_MAX)
+               v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
+                                    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+
+       if (ctrl->info->flags & UVC_CONTROL_GET_RES)
+               v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
+                                 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+
+       return 0;
 }
 
 
@@ -1246,7 +1270,7 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
        }
 
        ctrl->info = info;
-       ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL);
+       ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
        uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
                "entity %u\n", ctrl->info->entity, ctrl->info->selector,
                dev->udev->devpath, entity->id);
index 0c7966fdb83da07d67f523c25c768409d2474e6b..2bba059259e6ce9b5465490345c3e9f1dc9f0317 100644 (file)
@@ -245,7 +245,8 @@ struct uvc_control {
                           uvc_control_info. */
        __u8 dirty : 1,
             loaded : 1,
-            modified : 1;
+            modified : 1,
+            cached : 1;
 
        __u8 *data;
 };