aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/s5p-mfc
diff options
context:
space:
mode:
authorKamil Debski <k.debski@samsung.com>2013-01-11 10:29:33 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-04-12 11:38:56 -0400
commita34026e75bd1e6fdfbe8b59c320bb7d31c84b3da (patch)
treef41f223c059238337befc5145456a7310d3f623d /drivers/media/platform/s5p-mfc
parent81e096c8ac6a064854c2157e0bf802dc4906678c (diff)
[media] s5p-mfc: Add support for EOS command and EOS event in video decoder
Add support for V4L2_DEC_CMD_STOP command which will instruct MFC device to finish decoding and release all remaining frames kept for reference to the user. After dequeueing last decoded frame the driver will generate an V4L2_EVENT_EOS event. Signed-off-by: Kamil Debski <k.debski@samsung.com> Signed-off-by: Kyngmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/platform/s5p-mfc')
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c76
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c9
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c10
4 files changed, 92 insertions, 5 deletions
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 7379dc6dbebe..f608b7761be7 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -386,6 +386,8 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
386 } else { 386 } else {
387 mfc_debug(2, "MFC needs next buffer\n"); 387 mfc_debug(2, "MFC needs next buffer\n");
388 ctx->consumed_stream = 0; 388 ctx->consumed_stream = 0;
389 if (src_buf->flags & MFC_BUF_FLAG_EOS)
390 ctx->state = MFCINST_FINISHING;
389 list_del(&src_buf->list); 391 list_del(&src_buf->list);
390 ctx->src_queue_cnt--; 392 ctx->src_queue_cnt--;
391 if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0) 393 if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 4582473978ca..4af53bd2f182 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -22,6 +22,7 @@
22#include <linux/videodev2.h> 22#include <linux/videodev2.h>
23#include <linux/workqueue.h> 23#include <linux/workqueue.h>
24#include <media/v4l2-ctrls.h> 24#include <media/v4l2-ctrls.h>
25#include <media/v4l2-event.h>
25#include <media/videobuf2-core.h> 26#include <media/videobuf2-core.h>
26#include "s5p_mfc_common.h" 27#include "s5p_mfc_common.h"
27#include "s5p_mfc_debug.h" 28#include "s5p_mfc_debug.h"
@@ -623,17 +624,27 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
623/* Dequeue a buffer */ 624/* Dequeue a buffer */
624static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) 625static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
625{ 626{
627 const struct v4l2_event ev = {
628 .type = V4L2_EVENT_EOS
629 };
626 struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); 630 struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
631 int ret;
627 632
628 if (ctx->state == MFCINST_ERROR) { 633 if (ctx->state == MFCINST_ERROR) {
629 mfc_err("Call on DQBUF after unrecoverable error\n"); 634 mfc_err("Call on DQBUF after unrecoverable error\n");
630 return -EIO; 635 return -EIO;
631 } 636 }
632 if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 637 if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
633 return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); 638 ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
634 else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 639 else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
635 return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); 640 ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
636 return -EINVAL; 641 if (ret == 0 && ctx->state == MFCINST_FINISHED &&
642 list_empty(&ctx->vq_dst.done_list))
643 v4l2_event_queue_fh(&ctx->fh, &ev);
644 } else {
645 ret = -EINVAL;
646 }
647 return ret;
637} 648}
638 649
639/* Export DMA buffer */ 650/* Export DMA buffer */
@@ -809,6 +820,59 @@ static int vidioc_g_crop(struct file *file, void *priv,
809 return 0; 820 return 0;
810} 821}
811 822
823int vidioc_decoder_cmd(struct file *file, void *priv,
824 struct v4l2_decoder_cmd *cmd)
825{
826 struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
827 struct s5p_mfc_dev *dev = ctx->dev;
828 struct s5p_mfc_buf *buf;
829 unsigned long flags;
830
831 switch (cmd->cmd) {
832 case V4L2_ENC_CMD_STOP:
833 if (cmd->flags != 0)
834 return -EINVAL;
835
836 if (!ctx->vq_src.streaming)
837 return -EINVAL;
838
839 spin_lock_irqsave(&dev->irqlock, flags);
840 if (list_empty(&ctx->src_queue)) {
841 mfc_err("EOS: empty src queue, entering finishing state");
842 ctx->state = MFCINST_FINISHING;
843 if (s5p_mfc_ctx_ready(ctx))
844 set_work_bit_irqsave(ctx);
845 spin_unlock_irqrestore(&dev->irqlock, flags);
846 s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
847 } else {
848 mfc_err("EOS: marking last buffer of stream");
849 buf = list_entry(ctx->src_queue.prev,
850 struct s5p_mfc_buf, list);
851 if (buf->flags & MFC_BUF_FLAG_USED)
852 ctx->state = MFCINST_FINISHING;
853 else
854 buf->flags |= MFC_BUF_FLAG_EOS;
855 spin_unlock_irqrestore(&dev->irqlock, flags);
856 }
857 break;
858 default:
859 return -EINVAL;
860 }
861 return 0;
862}
863
864static int vidioc_subscribe_event(struct v4l2_fh *fh,
865 const struct v4l2_event_subscription *sub)
866{
867 switch (sub->type) {
868 case V4L2_EVENT_EOS:
869 return v4l2_event_subscribe(fh, sub, 2, NULL);
870 default:
871 return -EINVAL;
872 }
873}
874
875
812/* v4l2_ioctl_ops */ 876/* v4l2_ioctl_ops */
813static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { 877static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
814 .vidioc_querycap = vidioc_querycap, 878 .vidioc_querycap = vidioc_querycap,
@@ -830,6 +894,9 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
830 .vidioc_streamon = vidioc_streamon, 894 .vidioc_streamon = vidioc_streamon,
831 .vidioc_streamoff = vidioc_streamoff, 895 .vidioc_streamoff = vidioc_streamoff,
832 .vidioc_g_crop = vidioc_g_crop, 896 .vidioc_g_crop = vidioc_g_crop,
897 .vidioc_decoder_cmd = vidioc_decoder_cmd,
898 .vidioc_subscribe_event = vidioc_subscribe_event,
899 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
833}; 900};
834 901
835static int s5p_mfc_queue_setup(struct vb2_queue *vq, 902static int s5p_mfc_queue_setup(struct vb2_queue *vq,
@@ -1147,3 +1214,4 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx)
1147 mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n", 1214 mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n",
1148 (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt); 1215 (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt);
1149} 1216}
1217
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index c7ad329ca889..0af05a2d1cd4 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -1188,6 +1188,15 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
1188 unsigned long flags; 1188 unsigned long flags;
1189 unsigned int index; 1189 unsigned int index;
1190 1190
1191 if (ctx->state == MFCINST_FINISHING) {
1192 last_frame = MFC_DEC_LAST_FRAME;
1193 s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0);
1194 dev->curr_ctx = ctx->num;
1195 s5p_mfc_clean_ctx_int_flags(ctx);
1196 s5p_mfc_decode_one_frame_v5(ctx, last_frame);
1197 return 0;
1198 }
1199
1191 spin_lock_irqsave(&dev->irqlock, flags); 1200 spin_lock_irqsave(&dev->irqlock, flags);
1192 /* Frames are being decoded */ 1201 /* Frames are being decoded */
1193 if (list_empty(&ctx->src_queue)) { 1202 if (list_empty(&ctx->src_queue)) {
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index 33de88b8e9d0..db57f2539f2d 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -1363,8 +1363,16 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
1363 unsigned long flags; 1363 unsigned long flags;
1364 int last_frame = 0; 1364 int last_frame = 0;
1365 1365
1366 spin_lock_irqsave(&dev->irqlock, flags); 1366 if (ctx->state == MFCINST_FINISHING) {
1367 last_frame = MFC_DEC_LAST_FRAME;
1368 s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0);
1369 dev->curr_ctx = ctx->num;
1370 s5p_mfc_clean_ctx_int_flags(ctx);
1371 s5p_mfc_decode_one_frame_v6(ctx, last_frame);
1372 return 0;
1373 }
1367 1374
1375 spin_lock_irqsave(&dev->irqlock, flags);
1368 /* Frames are being decoded */ 1376 /* Frames are being decoded */
1369 if (list_empty(&ctx->src_queue)) { 1377 if (list_empty(&ctx->src_queue)) {
1370 mfc_debug(2, "No src buffers.\n"); 1378 mfc_debug(2, "No src buffers.\n");