diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 6b84c3413e83..ddbb52671c94 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -2113,6 +2113,12 @@ static int radio_s_tuner(struct file *file, void *priv, return 0; } +static void em28xx_free_v4l2_delayed(struct work_struct *work) +{ + kfree(container_of(to_delayed_work(work), + struct em28xx_v4l2, release)); +} + /* * em28xx_free_v4l2() - Free struct em28xx_v4l2 * @@ -2123,9 +2129,11 @@ static int radio_s_tuner(struct file *file, void *priv, static void em28xx_free_v4l2(struct kref *ref) { struct em28xx_v4l2 *v4l2 = container_of(ref, struct em28xx_v4l2, ref); + unsigned long delay = 100 * HZ; v4l2->dev->v4l2 = NULL; - kfree(v4l2); + INIT_DELAYED_WORK(&v4l2->release, em28xx_free_v4l2_delayed); + schedule_delayed_work(&v4l2->release, delay); } /* @@ -2153,13 +2161,17 @@ static int em28xx_v4l2_open(struct file *filp) return -EINVAL; } + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; + if (!dev->v4l2) { + mutex_unlock(&dev->lock); + return -ENOMEM; + } + em28xx_videodbg("open dev=%s type=%s users=%d\n", video_device_node_name(vdev), v4l2_type_names[fh_type], v4l2->users); - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - ret = v4l2_fh_open(filp); if (ret) { dev_err(&dev->intf->dev, diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index acbb62397314..e7ebb965e5bc 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -602,6 +602,7 @@ struct em28xx_v4l2 { struct media_pad video_pad, vbi_pad; struct media_entity *decoder; #endif + struct delayed_work release; }; struct em28xx_audio {