aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/uvc/uvc_driver.c1
-rw-r--r--drivers/media/video/uvc/uvc_status.c21
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c12
-rw-r--r--drivers/media/video/uvc/uvcvideo.h3
4 files changed, 34 insertions, 3 deletions
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index f4fced34cfd7..3287454bb368 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1594,6 +1594,7 @@ static int uvc_probe(struct usb_interface *intf,
1594 INIT_LIST_HEAD(&dev->entities); 1594 INIT_LIST_HEAD(&dev->entities);
1595 INIT_LIST_HEAD(&dev->streaming); 1595 INIT_LIST_HEAD(&dev->streaming);
1596 kref_init(&dev->kref); 1596 kref_init(&dev->kref);
1597 atomic_set(&dev->users, 0);
1597 1598
1598 dev->udev = usb_get_dev(udev); 1599 dev->udev = usb_get_dev(udev);
1599 dev->intf = usb_get_intf(intf); 1600 dev->intf = usb_get_intf(intf);
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
index 21d87124986b..f152a9903862 100644
--- a/drivers/media/video/uvc/uvc_status.c
+++ b/drivers/media/video/uvc/uvc_status.c
@@ -194,7 +194,7 @@ int uvc_status_init(struct uvc_device *dev)
194 dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, 194 dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
195 dev, interval); 195 dev, interval);
196 196
197 return usb_submit_urb(dev->int_urb, GFP_KERNEL); 197 return 0;
198} 198}
199 199
200void uvc_status_cleanup(struct uvc_device *dev) 200void uvc_status_cleanup(struct uvc_device *dev)
@@ -205,15 +205,30 @@ void uvc_status_cleanup(struct uvc_device *dev)
205 uvc_input_cleanup(dev); 205 uvc_input_cleanup(dev);
206} 206}
207 207
208int uvc_status_suspend(struct uvc_device *dev) 208int uvc_status_start(struct uvc_device *dev)
209{
210 if (dev->int_urb == NULL)
211 return 0;
212
213 return usb_submit_urb(dev->int_urb, GFP_KERNEL);
214}
215
216void uvc_status_stop(struct uvc_device *dev)
209{ 217{
210 usb_kill_urb(dev->int_urb); 218 usb_kill_urb(dev->int_urb);
219}
220
221int uvc_status_suspend(struct uvc_device *dev)
222{
223 if (atomic_read(&dev->users))
224 usb_kill_urb(dev->int_urb);
225
211 return 0; 226 return 0;
212} 227}
213 228
214int uvc_status_resume(struct uvc_device *dev) 229int uvc_status_resume(struct uvc_device *dev)
215{ 230{
216 if (dev->int_urb == NULL) 231 if (dev->int_urb == NULL || atomic_read(&dev->users) == 0)
217 return 0; 232 return 0;
218 233
219 return usb_submit_urb(dev->int_urb, GFP_NOIO); 234 return usb_submit_urb(dev->int_urb, GFP_NOIO);
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index ad7e64ff3add..507542dcbdae 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -439,6 +439,15 @@ static int uvc_v4l2_open(struct file *file)
439 goto done; 439 goto done;
440 } 440 }
441 441
442 if (atomic_inc_return(&video->dev->users) == 1) {
443 if ((ret = uvc_status_start(video->dev)) < 0) {
444 usb_autopm_put_interface(video->dev->intf);
445 atomic_dec(&video->dev->users);
446 kfree(handle);
447 goto done;
448 }
449 }
450
442 handle->device = video; 451 handle->device = video;
443 handle->state = UVC_HANDLE_PASSIVE; 452 handle->state = UVC_HANDLE_PASSIVE;
444 file->private_data = handle; 453 file->private_data = handle;
@@ -473,6 +482,9 @@ static int uvc_v4l2_release(struct file *file)
473 kfree(handle); 482 kfree(handle);
474 file->private_data = NULL; 483 file->private_data = NULL;
475 484
485 if (atomic_dec_return(&video->dev->users) == 0)
486 uvc_status_stop(video->dev);
487
476 usb_autopm_put_interface(video->dev->intf); 488 usb_autopm_put_interface(video->dev->intf);
477 kref_put(&video->dev->kref, uvc_delete); 489 kref_put(&video->dev->kref, uvc_delete);
478 return 0; 490 return 0;
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index e5014e668f99..daf074447304 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -634,6 +634,7 @@ struct uvc_device {
634 enum uvc_device_state state; 634 enum uvc_device_state state;
635 struct kref kref; 635 struct kref kref;
636 struct list_head list; 636 struct list_head list;
637 atomic_t users;
637 638
638 /* Video control interface */ 639 /* Video control interface */
639 __u16 uvc_version; 640 __u16 uvc_version;
@@ -770,6 +771,8 @@ extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
770/* Status */ 771/* Status */
771extern int uvc_status_init(struct uvc_device *dev); 772extern int uvc_status_init(struct uvc_device *dev);
772extern void uvc_status_cleanup(struct uvc_device *dev); 773extern void uvc_status_cleanup(struct uvc_device *dev);
774extern int uvc_status_start(struct uvc_device *dev);
775extern void uvc_status_stop(struct uvc_device *dev);
773extern int uvc_status_suspend(struct uvc_device *dev); 776extern int uvc_status_suspend(struct uvc_device *dev);
774extern int uvc_status_resume(struct uvc_device *dev); 777extern int uvc_status_resume(struct uvc_device *dev);
775 778