|
@@ -1196,12 +1196,19 @@ static int pwc_video_open(struct inode *inode, struct file *file)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+static void pwc_cleanup(struct pwc_device *pdev)
|
|
|
|
+{
|
|
|
|
+ pwc_remove_sysfs_files(pdev->vdev);
|
|
|
|
+ video_unregister_device(pdev->vdev);
|
|
|
|
+}
|
|
|
|
+
|
|
/* Note that all cleanup is done in the reverse order as in _open */
|
|
/* Note that all cleanup is done in the reverse order as in _open */
|
|
static int pwc_video_close(struct inode *inode, struct file *file)
|
|
static int pwc_video_close(struct inode *inode, struct file *file)
|
|
{
|
|
{
|
|
struct video_device *vdev = file->private_data;
|
|
struct video_device *vdev = file->private_data;
|
|
struct pwc_device *pdev;
|
|
struct pwc_device *pdev;
|
|
- int i;
|
|
|
|
|
|
+ int i, hint;
|
|
|
|
|
|
PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
|
|
PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
|
|
|
|
|
|
@@ -1224,8 +1231,9 @@ static int pwc_video_close(struct inode *inode, struct file *file)
|
|
pwc_isoc_cleanup(pdev);
|
|
pwc_isoc_cleanup(pdev);
|
|
pwc_free_buffers(pdev);
|
|
pwc_free_buffers(pdev);
|
|
|
|
|
|
|
|
+ lock_kernel();
|
|
/* Turn off LEDS and power down camera, but only when not unplugged */
|
|
/* Turn off LEDS and power down camera, but only when not unplugged */
|
|
- if (pdev->error_status != EPIPE) {
|
|
|
|
|
|
+ if (!pdev->unplugged) {
|
|
/* Turn LEDs off */
|
|
/* Turn LEDs off */
|
|
if (pwc_set_leds(pdev, 0, 0) < 0)
|
|
if (pwc_set_leds(pdev, 0, 0) < 0)
|
|
PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
|
|
PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
|
|
@@ -1234,9 +1242,19 @@ static int pwc_video_close(struct inode *inode, struct file *file)
|
|
if (i < 0)
|
|
if (i < 0)
|
|
PWC_ERROR("Failed to power down camera (%d)\n", i);
|
|
PWC_ERROR("Failed to power down camera (%d)\n", i);
|
|
}
|
|
}
|
|
|
|
+ pdev->vopen--;
|
|
|
|
+ PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", i);
|
|
|
|
+ } else {
|
|
|
|
+ pwc_cleanup(pdev);
|
|
|
|
+ /* Free memory (don't set pdev to 0 just yet) */
|
|
|
|
+ kfree(pdev);
|
|
|
|
+ /* search device_hint[] table if we occupy a slot, by any chance */
|
|
|
|
+ for (hint = 0; hint < MAX_DEV_HINTS; hint++)
|
|
|
|
+ if (device_hint[hint].pdev == pdev)
|
|
|
|
+ device_hint[hint].pdev = NULL;
|
|
}
|
|
}
|
|
- pdev->vopen--;
|
|
|
|
- PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
|
|
|
|
|
|
+ unlock_kernel();
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1791,21 +1809,21 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
|
|
/* Alert waiting processes */
|
|
/* Alert waiting processes */
|
|
wake_up_interruptible(&pdev->frameq);
|
|
wake_up_interruptible(&pdev->frameq);
|
|
/* Wait until device is closed */
|
|
/* Wait until device is closed */
|
|
- while (pdev->vopen)
|
|
|
|
- schedule();
|
|
|
|
- /* Device is now closed, so we can safely unregister it */
|
|
|
|
- PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
|
|
|
|
- pwc_remove_sysfs_files(pdev->vdev);
|
|
|
|
- video_unregister_device(pdev->vdev);
|
|
|
|
-
|
|
|
|
- /* Free memory (don't set pdev to 0 just yet) */
|
|
|
|
- kfree(pdev);
|
|
|
|
|
|
+ if(pdev->vopen) {
|
|
|
|
+ pdev->unplugged = 1;
|
|
|
|
+ } else {
|
|
|
|
+ /* Device is closed, so we can safely unregister it */
|
|
|
|
+ PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
|
|
|
|
+ pwc_cleanup(pdev);
|
|
|
|
+ /* Free memory (don't set pdev to 0 just yet) */
|
|
|
|
+ kfree(pdev);
|
|
|
|
|
|
disconnect_out:
|
|
disconnect_out:
|
|
- /* search device_hint[] table if we occupy a slot, by any chance */
|
|
|
|
- for (hint = 0; hint < MAX_DEV_HINTS; hint++)
|
|
|
|
- if (device_hint[hint].pdev == pdev)
|
|
|
|
- device_hint[hint].pdev = NULL;
|
|
|
|
|
|
+ /* search device_hint[] table if we occupy a slot, by any chance */
|
|
|
|
+ for (hint = 0; hint < MAX_DEV_HINTS; hint++)
|
|
|
|
+ if (device_hint[hint].pdev == pdev)
|
|
|
|
+ device_hint[hint].pdev = NULL;
|
|
|
|
+ }
|
|
|
|
|
|
unlock_kernel();
|
|
unlock_kernel();
|
|
}
|
|
}
|