diff options
Diffstat (limited to 'drivers/media/video/omap3isp/ispvideo.c')
-rw-r--r-- | drivers/media/video/omap3isp/ispvideo.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 9cd8f1a..f229057 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -26,6 +26,7 @@ #include <asm/cacheflush.h> #include <linux/clk.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/pagemap.h> #include <linux/scatterlist.h> #include <linux/sched.h> @@ -278,7 +279,8 @@ isp_video_far_end(struct isp_video *video) * limits reported by every block in the pipeline. * * Return 0 if all formats match, or -EPIPE if at least one link is found with - * different formats on its two ends. + * different formats on its two ends or if the pipeline doesn't start with a + * video source (either a subdev with no input pad, or a non-subdev entity). */ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) { @@ -329,10 +331,15 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) * in the middle of it. */ shifter_link = subdev == &isp->isp_ccdc.subdev; - /* Retrieve the source format */ + /* Retrieve the source format. Return an error if no source + * entity can be found, and stop checking the pipeline if the + * source entity isn't a subdev. + */ pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (pad == NULL) + return -EPIPE; + + if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) break; subdev = media_entity_to_v4l2_subdev(pad->entity); @@ -446,7 +453,7 @@ ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen) sgt->nents = sglen; sgt->orig_nents = sglen; - da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG); + da = omap_iommu_vmap(isp->domain, isp->iommu, 0, sgt, IOMMU_FLAG); if (IS_ERR_VALUE(da)) kfree(sgt); @@ -462,7 +469,7 @@ static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da) { struct sg_table *sgt; - sgt = iommu_vunmap(isp->iommu, (u32)da); + sgt = omap_iommu_vunmap(isp->domain, isp->iommu, (u32)da); kfree(sgt); } @@ -695,7 +702,6 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver)); strlcpy(cap->card, video->video.name, sizeof(cap->card)); strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); - cap->version = ISP_VIDEO_DRIVER_VERSION; if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; @@ -1051,6 +1057,14 @@ error: if (video->isp->pdata->set_constraints) video->isp->pdata->set_constraints(video->isp, false); media_entity_pipeline_stop(&video->video.entity); + /* The DMA queue must be emptied here, otherwise CCDC interrupts + * that will get triggered the next time the CCDC is powered up + * will try to access buffers that might have been freed but + * still present in the DMA queue. This can easily get triggered + * if the above omap3isp_pipeline_set_stream() call fails on a + * system with a free-running sensor. + */ + INIT_LIST_HEAD(&video->dmaqueue); video->queue = NULL; } @@ -1312,6 +1326,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name) return 0; } +void omap3isp_video_cleanup(struct isp_video *video) +{ + media_entity_cleanup(&video->video.entity); + mutex_destroy(&video->stream_lock); + mutex_destroy(&video->mutex); +} + int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) { int ret; @@ -1328,8 +1349,6 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) void omap3isp_video_unregister(struct isp_video *video) { - if (video_is_registered(&video->video)) { - media_entity_cleanup(&video->video.entity); + if (video_is_registered(&video->video)) video_unregister_device(&video->video); - } } |