Commit c1127134 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab

[media] pwc: Allow dqbuf / read to complete while waiting for controls

Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 6c9cac89
...@@ -1160,6 +1160,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1160,6 +1160,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pwc_construct(pdev); /* set min/max sizes correct */ pwc_construct(pdev); /* set min/max sizes correct */
mutex_init(&pdev->modlock); mutex_init(&pdev->modlock);
mutex_init(&pdev->udevlock);
spin_lock_init(&pdev->queued_bufs_lock); spin_lock_init(&pdev->queued_bufs_lock);
INIT_LIST_HEAD(&pdev->queued_bufs); INIT_LIST_HEAD(&pdev->queued_bufs);
...@@ -1297,6 +1298,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf) ...@@ -1297,6 +1298,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
{ {
struct pwc_device *pdev = usb_get_intfdata(intf); struct pwc_device *pdev = usb_get_intfdata(intf);
mutex_lock(&pdev->udevlock);
mutex_lock(&pdev->modlock); mutex_lock(&pdev->modlock);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
...@@ -1306,6 +1308,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf) ...@@ -1306,6 +1308,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
pdev->udev = NULL; pdev->udev = NULL;
mutex_unlock(&pdev->modlock); mutex_unlock(&pdev->modlock);
mutex_unlock(&pdev->udevlock);
pwc_remove_sysfs_files(pdev); pwc_remove_sysfs_files(pdev);
video_unregister_device(&pdev->vdev); video_unregister_device(&pdev->vdev);
......
...@@ -526,8 +526,24 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ...@@ -526,8 +526,24 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
container_of(ctrl->handler, struct pwc_device, ctrl_handler); container_of(ctrl->handler, struct pwc_device, ctrl_handler);
int ret = 0; int ret = 0;
if (!pdev->udev) /*
return -ENODEV; * Sometimes it can take quite long for the pwc to complete usb control
* transfers, so release the modlock to give streaming by another
* process / thread the chance to continue with a dqbuf.
*/
mutex_unlock(&pdev->modlock);
/*
* Take the udev-lock to protect against the disconnect handler
* completing and setting dev->udev to NULL underneath us. Other code
* does not need to do this since it is protected by the modlock.
*/
mutex_lock(&pdev->udevlock);
if (!pdev->udev) {
ret = -ENODEV;
goto leave;
}
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE: case V4L2_CID_AUTO_WHITE_BALANCE:
...@@ -590,6 +606,9 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ...@@ -590,6 +606,9 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
if (ret) if (ret)
PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret); PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret);
leave:
mutex_unlock(&pdev->udevlock);
mutex_lock(&pdev->modlock);
return ret; return ret;
} }
...@@ -751,8 +770,14 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) ...@@ -751,8 +770,14 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
container_of(ctrl->handler, struct pwc_device, ctrl_handler); container_of(ctrl->handler, struct pwc_device, ctrl_handler);
int ret = 0; int ret = 0;
if (!pdev->udev) /* See the comments on locking in pwc_g_volatile_ctrl */
return -ENODEV; mutex_unlock(&pdev->modlock);
mutex_lock(&pdev->udevlock);
if (!pdev->udev) {
ret = -ENODEV;
goto leave;
}
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS: case V4L2_CID_BRIGHTNESS:
...@@ -841,6 +866,9 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) ...@@ -841,6 +866,9 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
if (ret) if (ret)
PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret); PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret);
leave:
mutex_unlock(&pdev->udevlock);
mutex_lock(&pdev->modlock);
return ret; return ret;
} }
......
...@@ -200,6 +200,9 @@ struct pwc_device ...@@ -200,6 +200,9 @@ struct pwc_device
/* Pointer to our usb_device, may be NULL after unplug */ /* Pointer to our usb_device, may be NULL after unplug */
struct usb_device *udev; struct usb_device *udev;
/* Protects the setting of udev to NULL by our disconnect handler */
struct mutex udevlock;
/* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
int type; int type;
int release; /* release number */ int release; /* release number */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment