media: vicodec: correctly support unbinding of the driver
authorHans Verkuil <hverkuil@xs4all.nl>
Fri, 3 May 2019 14:22:49 +0000 (10:22 -0400)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Tue, 28 May 2019 16:25:08 +0000 (12:25 -0400)
Unbinding the driver while streaming caused the driver to hang.

The cause of this was failing to use the v4l2_device release
function and the use of devm_kmalloc for the state structure.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/platform/vicodec/vicodec-core.c

index bd01a92..8996125 100644 (file)
@@ -2013,18 +2013,31 @@ static int register_instance(struct vicodec_dev *dev,
        return 0;
 }
 
+static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev)
+{
+       struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+       v4l2_m2m_release(dev->stateful_enc.m2m_dev);
+       v4l2_m2m_release(dev->stateful_dec.m2m_dev);
+       v4l2_m2m_release(dev->stateless_dec.m2m_dev);
+       kfree(dev);
+}
+
 static int vicodec_probe(struct platform_device *pdev)
 {
        struct vicodec_dev *dev;
        int ret;
 
-       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
 
        ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
        if (ret)
-               return ret;
+               goto free_dev;
+
+       dev->v4l2_dev.release = vicodec_v4l2_dev_release;
 
 #ifdef CONFIG_MEDIA_CONTROLLER
        dev->mdev.dev = &pdev->dev;
@@ -2102,6 +2115,8 @@ unreg_sf_enc:
        v4l2_m2m_release(dev->stateful_enc.m2m_dev);
 unreg_dev:
        v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+       kfree(dev);
 
        return ret;
 }
@@ -2120,12 +2135,10 @@ static int vicodec_remove(struct platform_device *pdev)
        media_device_cleanup(&dev->mdev);
 #endif
 
-       v4l2_m2m_release(dev->stateful_enc.m2m_dev);
-       v4l2_m2m_release(dev->stateful_dec.m2m_dev);
        video_unregister_device(&dev->stateful_enc.vfd);
        video_unregister_device(&dev->stateful_dec.vfd);
        video_unregister_device(&dev->stateless_dec.vfd);
-       v4l2_device_unregister(&dev->v4l2_dev);
+       v4l2_device_put(&dev->v4l2_dev);
 
        return 0;
 }