aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc/uvc_v4l2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/uvc/uvc_v4l2.c')
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c60
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 */
377static int uvc_acquire_privileges(struct uvc_fh *handle) 377static 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;
395done:
396 mutex_unlock(&uvc_driver.open_mutex);
397 return ret;
398} 391}
399 392
400static void uvc_dismiss_privileges(struct uvc_fh *handle) 393static 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
461done:
462 mutex_unlock(&uvc_driver.open_mutex);
463 return ret;
464} 449}
465 450
466static int uvc_v4l2_release(struct file *file) 451static 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/*