diff options
Diffstat (limited to 'drivers/media/video/uvc/uvc_v4l2.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_v4l2.c | 60 |
1 files changed, 24 insertions, 36 deletions
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index a2bdd806efab..23239a4adefe 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c | |||
@@ -364,37 +364,30 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, | |||
364 | * unprivileged state. Only a single instance can be in a privileged state at | 364 | * unprivileged state. Only a single instance can be in a privileged state at |
365 | * a given time. Trying to perform an operation that requires privileges will | 365 | * a given time. Trying to perform an operation that requires privileges will |
366 | * automatically acquire the required privileges if possible, or return -EBUSY | 366 | * automatically acquire the required privileges if possible, or return -EBUSY |
367 | * otherwise. Privileges are dismissed when closing the instance. | 367 | * otherwise. Privileges are dismissed when closing the instance or when |
368 | * freeing the video buffers using VIDIOC_REQBUFS. | ||
368 | * | 369 | * |
369 | * Operations that require privileges are: | 370 | * Operations that require privileges are: |
370 | * | 371 | * |
371 | * - VIDIOC_S_INPUT | 372 | * - VIDIOC_S_INPUT |
372 | * - VIDIOC_S_PARM | 373 | * - VIDIOC_S_PARM |
373 | * - VIDIOC_S_FMT | 374 | * - VIDIOC_S_FMT |
374 | * - VIDIOC_TRY_FMT | ||
375 | * - VIDIOC_REQBUFS | 375 | * - VIDIOC_REQBUFS |
376 | */ | 376 | */ |
377 | static int uvc_acquire_privileges(struct uvc_fh *handle) | 377 | static int uvc_acquire_privileges(struct uvc_fh *handle) |
378 | { | 378 | { |
379 | int ret = 0; | ||
380 | |||
381 | /* Always succeed if the handle is already privileged. */ | 379 | /* Always succeed if the handle is already privileged. */ |
382 | if (handle->state == UVC_HANDLE_ACTIVE) | 380 | if (handle->state == UVC_HANDLE_ACTIVE) |
383 | return 0; | 381 | return 0; |
384 | 382 | ||
385 | /* Check if the device already has a privileged handle. */ | 383 | /* Check if the device already has a privileged handle. */ |
386 | mutex_lock(&uvc_driver.open_mutex); | ||
387 | if (atomic_inc_return(&handle->stream->active) != 1) { | 384 | if (atomic_inc_return(&handle->stream->active) != 1) { |
388 | atomic_dec(&handle->stream->active); | 385 | atomic_dec(&handle->stream->active); |
389 | ret = -EBUSY; | 386 | return -EBUSY; |
390 | goto done; | ||
391 | } | 387 | } |
392 | 388 | ||
393 | handle->state = UVC_HANDLE_ACTIVE; | 389 | handle->state = UVC_HANDLE_ACTIVE; |
394 | 390 | return 0; | |
395 | done: | ||
396 | mutex_unlock(&uvc_driver.open_mutex); | ||
397 | return ret; | ||
398 | } | 391 | } |
399 | 392 | ||
400 | static void uvc_dismiss_privileges(struct uvc_fh *handle) | 393 | static void uvc_dismiss_privileges(struct uvc_fh *handle) |
@@ -421,24 +414,20 @@ static int uvc_v4l2_open(struct file *file) | |||
421 | int ret = 0; | 414 | int ret = 0; |
422 | 415 | ||
423 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n"); | 416 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n"); |
424 | mutex_lock(&uvc_driver.open_mutex); | ||
425 | stream = video_drvdata(file); | 417 | stream = video_drvdata(file); |
426 | 418 | ||
427 | if (stream->dev->state & UVC_DEV_DISCONNECTED) { | 419 | if (stream->dev->state & UVC_DEV_DISCONNECTED) |
428 | ret = -ENODEV; | 420 | return -ENODEV; |
429 | goto done; | ||
430 | } | ||
431 | 421 | ||
432 | ret = usb_autopm_get_interface(stream->dev->intf); | 422 | ret = usb_autopm_get_interface(stream->dev->intf); |
433 | if (ret < 0) | 423 | if (ret < 0) |
434 | goto done; | 424 | return ret; |
435 | 425 | ||
436 | /* Create the device handle. */ | 426 | /* Create the device handle. */ |
437 | handle = kzalloc(sizeof *handle, GFP_KERNEL); | 427 | handle = kzalloc(sizeof *handle, GFP_KERNEL); |
438 | if (handle == NULL) { | 428 | if (handle == NULL) { |
439 | usb_autopm_put_interface(stream->dev->intf); | 429 | usb_autopm_put_interface(stream->dev->intf); |
440 | ret = -ENOMEM; | 430 | return -ENOMEM; |
441 | goto done; | ||
442 | } | 431 | } |
443 | 432 | ||
444 | if (atomic_inc_return(&stream->dev->users) == 1) { | 433 | if (atomic_inc_return(&stream->dev->users) == 1) { |
@@ -447,7 +436,7 @@ static int uvc_v4l2_open(struct file *file) | |||
447 | usb_autopm_put_interface(stream->dev->intf); | 436 | usb_autopm_put_interface(stream->dev->intf); |
448 | atomic_dec(&stream->dev->users); | 437 | atomic_dec(&stream->dev->users); |
449 | kfree(handle); | 438 | kfree(handle); |
450 | goto done; | 439 | return ret; |
451 | } | 440 | } |
452 | } | 441 | } |
453 | 442 | ||
@@ -456,11 +445,7 @@ static int uvc_v4l2_open(struct file *file) | |||
456 | handle->state = UVC_HANDLE_PASSIVE; | 445 | handle->state = UVC_HANDLE_PASSIVE; |
457 | file->private_data = handle; | 446 | file->private_data = handle; |
458 | 447 | ||
459 | kref_get(&stream->dev->kref); | 448 | return 0; |
460 | |||
461 | done: | ||
462 | mutex_unlock(&uvc_driver.open_mutex); | ||
463 | return ret; | ||
464 | } | 449 | } |
465 | 450 | ||
466 | static int uvc_v4l2_release(struct file *file) | 451 | static int uvc_v4l2_release(struct file *file) |
@@ -490,7 +475,6 @@ static int uvc_v4l2_release(struct file *file) | |||
490 | uvc_status_stop(stream->dev); | 475 | uvc_status_stop(stream->dev); |
491 | 476 | ||
492 | usb_autopm_put_interface(stream->dev->intf); | 477 | usb_autopm_put_interface(stream->dev->intf); |
493 | kref_put(&stream->dev->kref, uvc_delete); | ||
494 | return 0; | 478 | return 0; |
495 | } | 479 | } |
496 | 480 | ||
@@ -636,12 +620,16 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
636 | (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { | 620 | (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { |
637 | if (index != 0) | 621 | if (index != 0) |
638 | return -EINVAL; | 622 | return -EINVAL; |
639 | iterm = list_first_entry(&chain->iterms, | 623 | list_for_each_entry(iterm, &chain->entities, chain) { |
640 | struct uvc_entity, chain); | 624 | if (UVC_ENTITY_IS_ITERM(iterm)) |
625 | break; | ||
626 | } | ||
641 | pin = iterm->id; | 627 | pin = iterm->id; |
642 | } else if (pin < selector->selector.bNrInPins) { | 628 | } else if (pin < selector->bNrInPins) { |
643 | pin = selector->selector.baSourceID[index]; | 629 | pin = selector->baSourceID[index]; |
644 | list_for_each_entry(iterm, chain->iterms.next, chain) { | 630 | list_for_each_entry(iterm, &chain->entities, chain) { |
631 | if (!UVC_ENTITY_IS_ITERM(iterm)) | ||
632 | continue; | ||
645 | if (iterm->id == pin) | 633 | if (iterm->id == pin) |
646 | break; | 634 | break; |
647 | } | 635 | } |
@@ -692,7 +680,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
692 | break; | 680 | break; |
693 | } | 681 | } |
694 | 682 | ||
695 | if (input == 0 || input > chain->selector->selector.bNrInPins) | 683 | if (input == 0 || input > chain->selector->bNrInPins) |
696 | return -EINVAL; | 684 | return -EINVAL; |
697 | 685 | ||
698 | return uvc_query_ctrl(chain->dev, UVC_SET_CUR, | 686 | return uvc_query_ctrl(chain->dev, UVC_SET_CUR, |
@@ -731,9 +719,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
731 | { | 719 | { |
732 | struct uvc_streaming_control probe; | 720 | struct uvc_streaming_control probe; |
733 | 721 | ||
734 | if ((ret = uvc_acquire_privileges(handle)) < 0) | ||
735 | return ret; | ||
736 | |||
737 | return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL); | 722 | return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL); |
738 | } | 723 | } |
739 | 724 | ||
@@ -888,6 +873,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
888 | if (ret < 0) | 873 | if (ret < 0) |
889 | return ret; | 874 | return ret; |
890 | 875 | ||
876 | if (ret == 0) | ||
877 | uvc_dismiss_privileges(handle); | ||
878 | |||
891 | rb->count = ret; | 879 | rb->count = ret; |
892 | ret = 0; | 880 | ret = 0; |
893 | break; | 881 | break; |
@@ -1051,7 +1039,7 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data, | |||
1051 | size_t count, loff_t *ppos) | 1039 | size_t count, loff_t *ppos) |
1052 | { | 1040 | { |
1053 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n"); | 1041 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n"); |
1054 | return -ENODEV; | 1042 | return -EINVAL; |
1055 | } | 1043 | } |
1056 | 1044 | ||
1057 | /* | 1045 | /* |