diff options
Diffstat (limited to 'drivers/media/usb/uvc/uvc_v4l2.c')
| -rw-r--r-- | drivers/media/usb/uvc/uvc_v4l2.c | 49 |
1 files changed, 31 insertions, 18 deletions
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 8e056046bc2..378ae02e593 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -315,7 +315,7 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, goto done; } - memcpy(&stream->ctrl, &probe, sizeof probe); + stream->ctrl = probe; stream->cur_format = format; stream->cur_frame = frame; @@ -387,7 +387,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, return -EBUSY; } - memcpy(&probe, &stream->ctrl, sizeof probe); + probe = stream->ctrl; probe.dwFrameInterval = uvc_try_frame_interval(stream->cur_frame, interval); @@ -398,7 +398,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, return ret; } - memcpy(&stream->ctrl, &probe, sizeof probe); + stream->ctrl = probe; mutex_unlock(&stream->mutex); /* Return the actual frame period. */ @@ -498,16 +498,20 @@ static int uvc_v4l2_open(struct file *file) return -ENOMEM; } - if (atomic_inc_return(&stream->dev->users) == 1) { - ret = uvc_status_start(stream->dev); + mutex_lock(&stream->dev->lock); + if (stream->dev->users == 0) { + ret = uvc_status_start(stream->dev, GFP_KERNEL); if (ret < 0) { + mutex_unlock(&stream->dev->lock); usb_autopm_put_interface(stream->dev->intf); - atomic_dec(&stream->dev->users); kfree(handle); return ret; } } + stream->dev->users++; + mutex_unlock(&stream->dev->lock); + v4l2_fh_init(&handle->vfh, stream->vdev); v4l2_fh_add(&handle->vfh); handle->chain = stream->chain; @@ -538,8 +542,10 @@ static int uvc_v4l2_release(struct file *file) kfree(handle); file->private_data = NULL; - if (atomic_dec_return(&stream->dev->users) == 0) + mutex_lock(&stream->dev->lock); + if (--stream->dev->users == 0) uvc_status_stop(stream->dev); + mutex_unlock(&stream->dev->lock); usb_autopm_put_interface(stream->dev->intf); return 0; @@ -607,10 +613,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ret = uvc_ctrl_get(chain, &xctrl); uvc_ctrl_rollback(handle); - if (ret < 0) - return ret == -ENOENT ? -EINVAL : ret; - - ctrl->value = xctrl.value; + if (ret >= 0) + ctrl->value = xctrl.value; break; } @@ -634,7 +638,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ret = uvc_ctrl_set(chain, &xctrl); if (ret < 0) { uvc_ctrl_rollback(handle); - return ret == -ENOENT ? -EINVAL : ret; + return ret; } ret = uvc_ctrl_commit(handle, &xctrl, 1); if (ret == 0) @@ -659,9 +663,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ret = uvc_ctrl_get(chain, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); - ctrls->error_idx = ret == -ENOENT - ? ctrls->count : i; - return ret == -ENOENT ? -EINVAL : ret; + ctrls->error_idx = i; + return ret; } } ctrls->error_idx = 0; @@ -688,10 +691,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ret = uvc_ctrl_set(chain, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); - ctrls->error_idx = (ret == -ENOENT && - cmd == VIDIOC_S_EXT_CTRLS) + ctrls->error_idx = cmd == VIDIOC_S_EXT_CTRLS ? ctrls->count : i; - return ret == -ENOENT ? -EINVAL : ret; + return ret; } } @@ -998,6 +1000,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) return uvc_query_buffer(&stream->queue, buf); } + case VIDIOC_CREATE_BUFS: + { + struct v4l2_create_buffers *cb = arg; + + ret = uvc_acquire_privileges(handle); + if (ret < 0) + return ret; + + return uvc_create_buffers(&stream->queue, cb); + } + case VIDIOC_QBUF: if (!uvc_has_privileges(handle)) return -EBUSY; |
