pwc_construct(pdev); /* set min/max sizes correct */
mutex_init(&pdev->modlock);
+ mutex_init(&pdev->udevlock);
spin_lock_init(&pdev->queued_bufs_lock);
INIT_LIST_HEAD(&pdev->queued_bufs);
{
struct pwc_device *pdev = usb_get_intfdata(intf);
+ mutex_lock(&pdev->udevlock);
mutex_lock(&pdev->modlock);
usb_set_intfdata(intf, NULL);
pdev->udev = NULL;
mutex_unlock(&pdev->modlock);
+ mutex_unlock(&pdev->udevlock);
pwc_remove_sysfs_files(pdev);
video_unregister_device(&pdev->vdev);
container_of(ctrl->handler, struct pwc_device, ctrl_handler);
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) {
case V4L2_CID_AUTO_WHITE_BALANCE:
if (ret)
PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret);
+leave:
+ mutex_unlock(&pdev->udevlock);
+ mutex_lock(&pdev->modlock);
return ret;
}
container_of(ctrl->handler, struct pwc_device, ctrl_handler);
int ret = 0;
- if (!pdev->udev)
- return -ENODEV;
+ /* See the comments on locking in pwc_g_volatile_ctrl */
+ mutex_unlock(&pdev->modlock);
+ mutex_lock(&pdev->udevlock);
+
+ if (!pdev->udev) {
+ ret = -ENODEV;
+ goto leave;
+ }
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ret)
PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret);
+leave:
+ mutex_unlock(&pdev->udevlock);
+ mutex_lock(&pdev->modlock);
return ret;
}
/* Pointer to our usb_device, may be NULL after unplug */
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) */
int type;
int release; /* release number */