@@ -1919,11 +1919,41 @@ static void uvc_unregister_video(struct uvc_device *dev)
struct uvc_streaming *stream;
list_for_each_entry(stream, &dev->streams, list) {
+ /* Nothing to do here, continue. */
if (!video_is_registered(&stream->vdev))
continue;
+ /*
+ * For stream->vdev we follow the same logic as:
+ * vb2_video_unregister_device().
+ */
+
+ /* 1. Take a reference to vdev */
+ get_device(&stream->vdev.dev);
+
+ /* 2. Ensure that no new ioctls can be called. */
video_unregister_device(&stream->vdev);
- video_unregister_device(&stream->meta.vdev);
+
+ /* 3. Wait for old ioctls to finish. */
+ mutex_lock(&stream->mutex);
+
+ /* 4. Stop streaming. */
+ uvc_queue_release(&stream->queue);
+
+ mutex_unlock(&stream->mutex);
+
+ put_device(&stream->vdev.dev);
+
+ /*
+ * For stream->meta.vdev we can directly call:
+ * vb2_video_unregister_device().
+ */
+ vb2_video_unregister_device(&stream->meta.vdev);
+
+ /*
+ * Now both vdevs are not streaming and all the ioctls will
+ * return -ENODEV.
+ */
uvc_debugfs_cleanup_stream(stream);
}