summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc/uvc_v4l2.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2010-02-18 16:38:52 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-02 15:33:39 -0300
commit561474c2d2a1e212ea186e0b65cc69fb330e7bd5 (patch)
treeff01d7c41345625982ec594fe80b85dfb73b0942 /drivers/media/video/uvc/uvc_v4l2.c
parent3653639e5daf2ac5f4763e4f1b6cb57538184be9 (diff)
V4L/DVB: uvcvideo: Support menu controls in the control mapping API
The UVCIOC_CTRL_MAP ioctl doesn't support menu entries for menu controls. As the uvc_xu_control_mapping structure has no reserved fields, this can't be fixed while keeping ABI compatibility. Modify the UVCIOC_CTRL_MAP ioctl to add menu entries support, and define UVCIOC_CTRL_MAP_OLD that supports the old ABI without any ability to add menu controls. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/uvc/uvc_v4l2.c')
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c92
1 files changed, 69 insertions, 23 deletions
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 7c9ab293349..485a89912ce 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -29,6 +29,71 @@
#include "uvcvideo.h"
/* ------------------------------------------------------------------------
+ * UVC ioctls
+ */
+static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
+{
+ struct uvc_control_mapping *map;
+ unsigned int size;
+ int ret;
+
+ map = kzalloc(sizeof *map, GFP_KERNEL);
+ if (map == NULL)
+ return -ENOMEM;
+
+ map->id = xmap->id;
+ memcpy(map->name, xmap->name, sizeof map->name);
+ memcpy(map->entity, xmap->entity, sizeof map->entity);
+ map->selector = xmap->selector;
+ map->size = xmap->size;
+ map->offset = xmap->offset;
+ map->v4l2_type = xmap->v4l2_type;
+ map->data_type = xmap->data_type;
+
+ switch (xmap->v4l2_type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ case V4L2_CTRL_TYPE_BUTTON:
+ break;
+
+ case V4L2_CTRL_TYPE_MENU:
+ if (old) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ size = xmap->menu_count * sizeof(*map->menu_info);
+ map->menu_info = kmalloc(size, GFP_KERNEL);
+ if (map->menu_info == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ map->menu_count = xmap->menu_count;
+ break;
+
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = uvc_ctrl_add_mapping(map);
+
+done:
+ if (ret < 0) {
+ kfree(map->menu_info);
+ kfree(map);
+ }
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------
* V4L2 interface
*/
@@ -974,7 +1039,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
info->flags = xinfo->flags;
info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
+ UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF |
+ UVC_CONTROL_EXTENSION;
ret = uvc_ctrl_add_info(info);
if (ret < 0)
@@ -982,32 +1048,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
break;
}
+ case UVCIOC_CTRL_MAP_OLD:
case UVCIOC_CTRL_MAP:
- {
- struct uvc_xu_control_mapping *xmap = arg;
- struct uvc_control_mapping *map;
-
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- map = kzalloc(sizeof *map, GFP_KERNEL);
- if (map == NULL)
- return -ENOMEM;
-
- map->id = xmap->id;
- memcpy(map->name, xmap->name, sizeof map->name);
- memcpy(map->entity, xmap->entity, sizeof map->entity);
- map->selector = xmap->selector;
- map->size = xmap->size;
- map->offset = xmap->offset;
- map->v4l2_type = xmap->v4l2_type;
- map->data_type = xmap->data_type;
-
- ret = uvc_ctrl_add_mapping(map);
- if (ret < 0)
- kfree(map);
- break;
- }
+ return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD);
case UVCIOC_CTRL_GET:
return uvc_xu_ctrl_query(chain, arg, 0);