diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2010-02-18 16:38:52 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-02 15:33:39 -0300 |
commit | 561474c2d2a1e212ea186e0b65cc69fb330e7bd5 (patch) | |
tree | ff01d7c41345625982ec594fe80b85dfb73b0942 /drivers/media/video/uvc/uvc_v4l2.c | |
parent | 3653639e5daf2ac5f4763e4f1b6cb57538184be9 (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.c | 92 |
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); |