aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@skynet.be>2009-05-19 09:08:03 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-06-16 17:21:10 -0400
commit04a37e0f32f9882430bc1899899d2ed91b8aaf5b (patch)
tree65af84e6e1165d1878d34c4a3dcefce881f3b955 /drivers/media/video/uvc
parentb2d9cc4226fa512aa36fd78738f5069dfce0583d (diff)
V4L/DVB (11837): uvcvideo: Start status polling on device open
Most UVC camera include an interrupt endpoint to report control value changes, video streaming errors and camera button events. The USB controller continuously polls the interrupt endpoint to retrieve such events. This prevents the device from being auto-suspended, and thus consumes power. Reporting video streaming errors don't make sense when the V4L2 device is closed. Control value changes are probably useless as well if nobody listens to the events, although caching will probably have to be completely disabled then. No polling is thus be required when /dev/videoX is not opened. To enable auto-suspend and save power do not poll the interrupt endpoint until the device is open. We lose the ability to detect button events if no application is using the camera. http://bugzilla.kernel.org/show_bug.cgi?id=11948 Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/uvc')
-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