summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/omap3isp/ispvideo.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/omap3isp/ispvideo.c')
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c147
1 files changed, 99 insertions, 48 deletions
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index ecadca3e945b..ac76d2901501 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -22,8 +22,10 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
#include <media/videobuf2-dma-contig.h>
#include "ispvideo.h"
@@ -210,8 +212,7 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
remote = media_entity_remote_pad(&video->pad);
- if (remote == NULL ||
- media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
if (pad)
@@ -226,16 +227,23 @@ static int isp_video_get_graph_data(struct isp_video *video,
{
struct media_entity_graph graph;
struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->parent;
+ struct media_device *mdev = entity->graph_obj.mdev;
struct isp_video *far_end = NULL;
+ int ret;
mutex_lock(&mdev->graph_mutex);
+ ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ return ret;
+ }
+
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
struct isp_video *__video;
- pipe->entities |= 1 << entity->id;
+ media_entity_enum_set(&pipe->ent_enum, entity);
if (far_end != NULL)
continue;
@@ -243,7 +251,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
if (entity == &video->video.entity)
continue;
- if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+ if (!is_media_entity_v4l2_io(entity))
continue;
__video = to_isp_video(media_entity_to_video_device(entity));
@@ -253,6 +261,8 @@ static int isp_video_get_graph_data(struct isp_video *video,
mutex_unlock(&mdev->graph_mutex);
+ media_entity_graph_walk_cleanup(&graph);
+
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
pipe->input = far_end;
pipe->output = video;
@@ -426,10 +436,68 @@ static void isp_video_buffer_queue(struct vb2_buffer *buf)
}
}
+/*
+ * omap3isp_video_return_buffers - Return all queued buffers to videobuf2
+ * @video: ISP video object
+ * @state: new state for the returned buffers
+ *
+ * Return all buffers queued on the video node to videobuf2 in the given state.
+ * The buffer state should be VB2_BUF_STATE_QUEUED if called due to an error
+ * when starting the stream, or VB2_BUF_STATE_ERROR otherwise.
+ *
+ * The function must be called with the video irqlock held.
+ */
+static void omap3isp_video_return_buffers(struct isp_video *video,
+ enum vb2_buffer_state state)
+{
+ while (!list_empty(&video->dmaqueue)) {
+ struct isp_buffer *buf;
+
+ buf = list_first_entry(&video->dmaqueue,
+ struct isp_buffer, irqlist);
+ list_del(&buf->irqlist);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
+}
+
+static int isp_video_start_streaming(struct vb2_queue *queue,
+ unsigned int count)
+{
+ struct isp_video_fh *vfh = vb2_get_drv_priv(queue);
+ struct isp_video *video = vfh->video;
+ struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+ unsigned long flags;
+ int ret;
+
+ /* In sensor-to-memory mode, the stream can be started synchronously
+ * to the stream on command. In memory-to-memory mode, it will be
+ * started when buffers are queued on both the input and output.
+ */
+ if (pipe->input)
+ return 0;
+
+ ret = omap3isp_pipeline_set_stream(pipe,
+ ISP_PIPELINE_STREAM_CONTINUOUS);
+ if (ret < 0) {
+ spin_lock_irqsave(&video->irqlock, flags);
+ omap3isp_video_return_buffers(video, VB2_BUF_STATE_QUEUED);
+ spin_unlock_irqrestore(&video->irqlock, flags);
+ return ret;
+ }
+
+ spin_lock_irqsave(&video->irqlock, flags);
+ if (list_empty(&video->dmaqueue))
+ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+ spin_unlock_irqrestore(&video->irqlock, flags);
+
+ return 0;
+}
+
static const struct vb2_ops isp_video_queue_ops = {
.queue_setup = isp_video_queue_setup,
.buf_prepare = isp_video_buffer_prepare,
.buf_queue = isp_video_buffer_queue,
+ .start_streaming = isp_video_start_streaming,
};
/*
@@ -451,7 +519,7 @@ static const struct vb2_ops isp_video_queue_ops = {
struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
{
struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
- enum isp_pipeline_state state;
+ enum vb2_buffer_state vb_state;
struct isp_buffer *buf;
unsigned long flags;
@@ -487,17 +555,19 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
/* Report pipeline errors to userspace on the capture device side. */
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
- state = VB2_BUF_STATE_ERROR;
+ vb_state = VB2_BUF_STATE_ERROR;
pipe->error = false;
} else {
- state = VB2_BUF_STATE_DONE;
+ vb_state = VB2_BUF_STATE_DONE;
}
- vb2_buffer_done(&buf->vb.vb2_buf, state);
+ vb2_buffer_done(&buf->vb.vb2_buf, vb_state);
spin_lock_irqsave(&video->irqlock, flags);
if (list_empty(&video->dmaqueue)) {
+ enum isp_pipeline_state state;
+
spin_unlock_irqrestore(&video->irqlock, flags);
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -533,26 +603,16 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
* omap3isp_video_cancel_stream - Cancel stream on a video node
* @video: ISP video object
*
- * Cancelling a stream mark all buffers on the video node as erroneous and makes
- * sure no new buffer can be queued.
+ * Cancelling a stream returns all buffers queued on the video node to videobuf2
+ * in the erroneous state and makes sure no new buffer can be queued.
*/
void omap3isp_video_cancel_stream(struct isp_video *video)
{
unsigned long flags;
spin_lock_irqsave(&video->irqlock, flags);
-
- while (!list_empty(&video->dmaqueue)) {
- struct isp_buffer *buf;
-
- buf = list_first_entry(&video->dmaqueue,
- struct isp_buffer, irqlist);
- list_del(&buf->irqlist);
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- }
-
+ omap3isp_video_return_buffers(video, VB2_BUF_STATE_ERROR);
video->error = true;
-
spin_unlock_irqrestore(&video->irqlock, flags);
}
@@ -900,7 +960,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
for (i = 0; i < ARRAY_SIZE(ents); i++) {
/* Is the entity part of the pipeline? */
- if (!(pipe->entities & (1 << ents[i]->id)))
+ if (!media_entity_enum_test(&pipe->ent_enum, ents[i]))
continue;
/* ISP entities have always sink pad == 0. Find source. */
@@ -918,7 +978,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
return -EINVAL;
}
- if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV)
+ if (!is_media_entity_v4l2_subdev(source))
return 0;
pipe->external = media_entity_to_v4l2_subdev(source);
@@ -952,7 +1012,8 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
pipe->external_rate = ctrl.value64;
- if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) {
+ if (media_entity_enum_test(&pipe->ent_enum,
+ &isp->isp_ccdc.subdev.entity)) {
unsigned int rate = UINT_MAX;
/*
* Check that maximum allowed CCDC pixel rate isn't
@@ -1018,7 +1079,9 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
pipe = video->video.entity.pipe
? to_isp_pipeline(&video->video.entity) : &video->pipe;
- pipe->entities = 0;
+ ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev);
+ if (ret)
+ goto err_enum_init;
/* TODO: Implement PM QoS */
pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
@@ -1076,28 +1139,10 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
goto err_check_format;
- /* In sensor-to-memory mode, the stream can be started synchronously
- * to the stream on command. In memory-to-memory mode, it will be
- * started when buffers are queued on both the input and output.
- */
- if (pipe->input == NULL) {
- ret = omap3isp_pipeline_set_stream(pipe,
- ISP_PIPELINE_STREAM_CONTINUOUS);
- if (ret < 0)
- goto err_set_stream;
- spin_lock_irqsave(&video->irqlock, flags);
- if (list_empty(&video->dmaqueue))
- video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
- spin_unlock_irqrestore(&video->irqlock, flags);
- }
-
mutex_unlock(&video->stream_lock);
+
return 0;
-err_set_stream:
- mutex_lock(&video->queue_lock);
- vb2_streamoff(&vfh->queue, type);
- mutex_unlock(&video->queue_lock);
err_check_format:
media_entity_pipeline_stop(&video->video.entity);
err_pipeline_start:
@@ -1112,7 +1157,11 @@ err_pipeline_start:
INIT_LIST_HEAD(&video->dmaqueue);
video->queue = NULL;
+ media_entity_enum_cleanup(&pipe->ent_enum);
+
+err_enum_init:
mutex_unlock(&video->stream_lock);
+
return ret;
}
@@ -1164,6 +1213,8 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
/* TODO: Implement PM QoS */
media_entity_pipeline_stop(&video->video.entity);
+ media_entity_enum_cleanup(&pipe->ent_enum);
+
done:
mutex_unlock(&video->stream_lock);
return 0;
@@ -1243,7 +1294,7 @@ static int isp_video_open(struct file *file)
goto done;
}
- ret = omap3isp_pipeline_pm_use(&video->video.entity, 1);
+ ret = v4l2_pipeline_pm_use(&video->video.entity, 1);
if (ret < 0) {
omap3isp_put(video->isp);
goto done;
@@ -1293,7 +1344,7 @@ static int isp_video_release(struct file *file)
vb2_queue_release(&handle->queue);
mutex_unlock(&video->queue_lock);
- omap3isp_pipeline_pm_use(&video->video.entity, 0);
+ v4l2_pipeline_pm_use(&video->video.entity, 0);
/* Release the file handle. */
v4l2_fh_del(vfh);
@@ -1367,7 +1418,7 @@ int omap3isp_video_init(struct isp_video *video, const char *name)
if (IS_ERR(video->alloc_ctx))
return PTR_ERR(video->alloc_ctx);
- ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
+ ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
if (ret < 0) {
vb2_dma_contig_cleanup_ctx(video->alloc_ctx);
return ret;
OpenPOWER on IntegriCloud