diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 1 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_status.c | 21 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_v4l2.c | 12 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 3 |
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 | ||
200 | void uvc_status_cleanup(struct uvc_device *dev) | 200 | void 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 | ||
208 | int uvc_status_suspend(struct uvc_device *dev) | 208 | int 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 | |||
216 | void 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 | |||
221 | int 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 | ||
214 | int uvc_status_resume(struct uvc_device *dev) | 229 | int 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 */ |
771 | extern int uvc_status_init(struct uvc_device *dev); | 772 | extern int uvc_status_init(struct uvc_device *dev); |
772 | extern void uvc_status_cleanup(struct uvc_device *dev); | 773 | extern void uvc_status_cleanup(struct uvc_device *dev); |
774 | extern int uvc_status_start(struct uvc_device *dev); | ||
775 | extern void uvc_status_stop(struct uvc_device *dev); | ||
773 | extern int uvc_status_suspend(struct uvc_device *dev); | 776 | extern int uvc_status_suspend(struct uvc_device *dev); |
774 | extern int uvc_status_resume(struct uvc_device *dev); | 777 | extern int uvc_status_resume(struct uvc_device *dev); |
775 | 778 | ||