aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pwc
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2011-07-03 10:50:51 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:53:45 -0400
commitc11271349ad5d4647e69e511fc481b2dd390efc4 (patch)
treebc9ecda60fb903856dae5e21271e449e203a14bc /drivers/media/video/pwc
parent6c9cac89c009c049a9ad29cdf0f51892410fe751 (diff)
[media] pwc: Allow dqbuf / read to complete while waiting for controls
Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/pwc')
-rw-r--r--drivers/media/video/pwc/pwc-if.c3
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c36
-rw-r--r--drivers/media/video/pwc/pwc.h3
3 files changed, 38 insertions, 4 deletions
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 1d5a6db915fa..fdf113fe51c3 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1160,6 +1160,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
1160 pwc_construct(pdev); /* set min/max sizes correct */ 1160 pwc_construct(pdev); /* set min/max sizes correct */
1161 1161
1162 mutex_init(&pdev->modlock); 1162 mutex_init(&pdev->modlock);
1163 mutex_init(&pdev->udevlock);
1163 spin_lock_init(&pdev->queued_bufs_lock); 1164 spin_lock_init(&pdev->queued_bufs_lock);
1164 INIT_LIST_HEAD(&pdev->queued_bufs); 1165 INIT_LIST_HEAD(&pdev->queued_bufs);
1165 1166
@@ -1297,6 +1298,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
1297{ 1298{
1298 struct pwc_device *pdev = usb_get_intfdata(intf); 1299 struct pwc_device *pdev = usb_get_intfdata(intf);
1299 1300
1301 mutex_lock(&pdev->udevlock);
1300 mutex_lock(&pdev->modlock); 1302 mutex_lock(&pdev->modlock);
1301 1303
1302 usb_set_intfdata(intf, NULL); 1304 usb_set_intfdata(intf, NULL);
@@ -1306,6 +1308,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
1306 pdev->udev = NULL; 1308 pdev->udev = NULL;
1307 1309
1308 mutex_unlock(&pdev->modlock); 1310 mutex_unlock(&pdev->modlock);
1311 mutex_unlock(&pdev->udevlock);
1309 1312
1310 pwc_remove_sysfs_files(pdev); 1313 pwc_remove_sysfs_files(pdev);
1311 video_unregister_device(&pdev->vdev); 1314 video_unregister_device(&pdev->vdev);
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 986dd5d6187a..537657283e79 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -526,8 +526,24 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
526 container_of(ctrl->handler, struct pwc_device, ctrl_handler); 526 container_of(ctrl->handler, struct pwc_device, ctrl_handler);
527 int ret = 0; 527 int ret = 0;
528 528
529 if (!pdev->udev) 529 /*
530 return -ENODEV; 530 * Sometimes it can take quite long for the pwc to complete usb control
531 * transfers, so release the modlock to give streaming by another
532 * process / thread the chance to continue with a dqbuf.
533 */
534 mutex_unlock(&pdev->modlock);
535
536 /*
537 * Take the udev-lock to protect against the disconnect handler
538 * completing and setting dev->udev to NULL underneath us. Other code
539 * does not need to do this since it is protected by the modlock.
540 */
541 mutex_lock(&pdev->udevlock);
542
543 if (!pdev->udev) {
544 ret = -ENODEV;
545 goto leave;
546 }
531 547
532 switch (ctrl->id) { 548 switch (ctrl->id) {
533 case V4L2_CID_AUTO_WHITE_BALANCE: 549 case V4L2_CID_AUTO_WHITE_BALANCE:
@@ -590,6 +606,9 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
590 if (ret) 606 if (ret)
591 PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret); 607 PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret);
592 608
609leave:
610 mutex_unlock(&pdev->udevlock);
611 mutex_lock(&pdev->modlock);
593 return ret; 612 return ret;
594} 613}
595 614
@@ -751,8 +770,14 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
751 container_of(ctrl->handler, struct pwc_device, ctrl_handler); 770 container_of(ctrl->handler, struct pwc_device, ctrl_handler);
752 int ret = 0; 771 int ret = 0;
753 772
754 if (!pdev->udev) 773 /* See the comments on locking in pwc_g_volatile_ctrl */
755 return -ENODEV; 774 mutex_unlock(&pdev->modlock);
775 mutex_lock(&pdev->udevlock);
776
777 if (!pdev->udev) {
778 ret = -ENODEV;
779 goto leave;
780 }
756 781
757 switch (ctrl->id) { 782 switch (ctrl->id) {
758 case V4L2_CID_BRIGHTNESS: 783 case V4L2_CID_BRIGHTNESS:
@@ -841,6 +866,9 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
841 if (ret) 866 if (ret)
842 PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret); 867 PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret);
843 868
869leave:
870 mutex_unlock(&pdev->udevlock);
871 mutex_lock(&pdev->modlock);
844 return ret; 872 return ret;
845} 873}
846 874
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 601a549988b5..e02dbf745155 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -200,6 +200,9 @@ struct pwc_device
200 200
201 /* Pointer to our usb_device, may be NULL after unplug */ 201 /* Pointer to our usb_device, may be NULL after unplug */
202 struct usb_device *udev; 202 struct usb_device *udev;
203 /* Protects the setting of udev to NULL by our disconnect handler */
204 struct mutex udevlock;
205
203 /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ 206 /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
204 int type; 207 int type;
205 int release; /* release number */ 208 int release; /* release number */