diff options
Diffstat (limited to 'drivers/media/usb/uvc/uvc_v4l2.c')
-rw-r--r-- | drivers/media/usb/uvc/uvc_v4l2.c | 103 |
1 files changed, 40 insertions, 63 deletions
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 6acb8013de08..f4e4aff8ddf7 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -40,7 +40,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, return -ENOMEM; map->id = xmap->id; - memcpy(map->name, xmap->name, sizeof(map->name)); + /* Non standard control id. */ + if (v4l2_ctrl_get_name(map->id) == NULL) { + map->name = kmemdup(xmap->name, sizeof(xmap->name), + GFP_KERNEL); + if (!map->name) + return -ENOMEM; + } memcpy(map->entity, xmap->entity, sizeof(map->entity)); map->selector = xmap->selector; map->size = xmap->size; @@ -472,10 +478,13 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, uvc_simplify_fraction(&timeperframe.numerator, &timeperframe.denominator, 8, 333); - if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { parm->parm.capture.timeperframe = timeperframe; - else + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + } else { parm->parm.output.timeperframe = timeperframe; + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + } return 0; } @@ -614,13 +623,12 @@ static int uvc_v4l2_release(struct file *file) static int uvc_ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct uvc_fh *handle = file->private_data; struct uvc_video_chain *chain = handle->chain; struct uvc_streaming *stream = handle->stream; strscpy(cap->driver, "uvcvideo", sizeof(cap->driver)); - strscpy(cap->card, vdev->name, sizeof(cap->card)); + strscpy(cap->card, handle->stream->dev->name, sizeof(cap->card)); usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING | chain->caps; @@ -995,58 +1003,24 @@ static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, return 0; } -static int uvc_ioctl_g_ctrl(struct file *file, void *fh, - struct v4l2_control *ctrl) +static int uvc_ctrl_check_access(struct uvc_video_chain *chain, + struct v4l2_ext_controls *ctrls, + unsigned long ioctl) { - struct uvc_fh *handle = fh; - struct uvc_video_chain *chain = handle->chain; - struct v4l2_ext_control xctrl; - int ret; - - memset(&xctrl, 0, sizeof(xctrl)); - xctrl.id = ctrl->id; - - ret = uvc_ctrl_begin(chain); - if (ret < 0) - return ret; - - ret = uvc_ctrl_get(chain, &xctrl); - uvc_ctrl_rollback(handle); - if (ret < 0) - return ret; - - ctrl->value = xctrl.value; - return 0; -} - -static int uvc_ioctl_s_ctrl(struct file *file, void *fh, - struct v4l2_control *ctrl) -{ - struct uvc_fh *handle = fh; - struct uvc_video_chain *chain = handle->chain; - struct v4l2_ext_control xctrl; - int ret; - - memset(&xctrl, 0, sizeof(xctrl)); - xctrl.id = ctrl->id; - xctrl.value = ctrl->value; - - ret = uvc_ctrl_begin(chain); - if (ret < 0) - return ret; + struct v4l2_ext_control *ctrl = ctrls->controls; + unsigned int i; + int ret = 0; - ret = uvc_ctrl_set(handle, &xctrl); - if (ret < 0) { - uvc_ctrl_rollback(handle); - return ret; + for (i = 0; i < ctrls->count; ++ctrl, ++i) { + ret = uvc_ctrl_is_accessible(chain, ctrl->id, + ioctl == VIDIOC_G_EXT_CTRLS); + if (ret) + break; } - ret = uvc_ctrl_commit(handle, &xctrl, 1); - if (ret < 0) - return ret; + ctrls->error_idx = ioctl == VIDIOC_TRY_EXT_CTRLS ? i : ctrls->count; - ctrl->value = xctrl.value; - return 0; + return ret; } static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, @@ -1058,6 +1032,10 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, unsigned int i; int ret; + ret = uvc_ctrl_check_access(chain, ctrls, VIDIOC_G_EXT_CTRLS); + if (ret < 0) + return ret; + if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) { for (i = 0; i < ctrls->count; ++ctrl, ++i) { struct v4l2_queryctrl qc = { .id = ctrl->id }; @@ -1094,16 +1072,16 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, struct v4l2_ext_controls *ctrls, - bool commit) + unsigned long ioctl) { struct v4l2_ext_control *ctrl = ctrls->controls; struct uvc_video_chain *chain = handle->chain; unsigned int i; int ret; - /* Default value cannot be changed */ - if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) - return -EINVAL; + ret = uvc_ctrl_check_access(chain, ctrls, ioctl); + if (ret < 0) + return ret; ret = uvc_ctrl_begin(chain); if (ret < 0) @@ -1113,15 +1091,16 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, ret = uvc_ctrl_set(handle, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); - ctrls->error_idx = commit ? ctrls->count : i; + ctrls->error_idx = ioctl == VIDIOC_S_EXT_CTRLS ? + ctrls->count : i; return ret; } } ctrls->error_idx = 0; - if (commit) - return uvc_ctrl_commit(handle, ctrls->controls, ctrls->count); + if (ioctl == VIDIOC_S_EXT_CTRLS) + return uvc_ctrl_commit(handle, ctrls); else return uvc_ctrl_rollback(handle); } @@ -1131,7 +1110,7 @@ static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, { struct uvc_fh *handle = fh; - return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, true); + return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS); } static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, @@ -1139,7 +1118,7 @@ static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, { struct uvc_fh *handle = fh; - return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, false); + return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS); } static int uvc_ioctl_querymenu(struct file *file, void *fh, @@ -1538,8 +1517,6 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = { .vidioc_s_input = uvc_ioctl_s_input, .vidioc_queryctrl = uvc_ioctl_queryctrl, .vidioc_query_ext_ctrl = uvc_ioctl_query_ext_ctrl, - .vidioc_g_ctrl = uvc_ioctl_g_ctrl, - .vidioc_s_ctrl = uvc_ioctl_s_ctrl, .vidioc_g_ext_ctrls = uvc_ioctl_g_ext_ctrls, .vidioc_s_ext_ctrls = uvc_ioctl_s_ext_ctrls, .vidioc_try_ext_ctrls = uvc_ioctl_try_ext_ctrls, |