aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2019-07-17 11:30:43 +0200
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2019-07-30 08:40:25 +0200
commit1b0c1c2fefe84b347e0e078d0eff7539ad8a381e (patch)
tree6e1116fe526c4ff9ba905a16f3e9d4f436ede966
parent37bcf2671e838334f807ca6f4871ae317a28599f (diff)
m2m-deinterlace: fix compliance issuesm2m-deinterlace
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--drivers/media/platform/m2m-deinterlace.c172
1 files changed, 122 insertions, 50 deletions
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 9ad24c86c5ab..b1c3418d68c4 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -34,7 +34,7 @@ module_param(debug, bool, 0644);
#define MEM2MEM_NAME "m2m-deinterlace"
#define dprintk(dev, fmt, arg...) \
- v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+ v4l2_info(&dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
struct deinterlace_fmt {
u32 fourcc;
@@ -62,6 +62,7 @@ struct deinterlace_q_data {
unsigned int sizeimage;
struct deinterlace_fmt *fmt;
enum v4l2_field field;
+ unsigned int sequence;
};
enum {
@@ -124,7 +125,6 @@ struct deinterlace_dev {
atomic_t busy;
struct mutex dev_mutex;
- spinlock_t irqlock;
struct dma_chan *dma_chan;
@@ -135,9 +135,10 @@ struct deinterlace_ctx {
struct v4l2_fh fh;
struct deinterlace_dev *dev;
- /* Abort requested by m2m */
- int aborting;
enum v4l2_colorspace colorspace;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_xfer_func xfer_func;
+ enum v4l2_quantization quant;
dma_cookie_t cookie;
struct dma_interleaved_template *xt;
};
@@ -162,38 +163,30 @@ static int deinterlace_job_ready(void *priv)
return 0;
}
-static void deinterlace_job_abort(void *priv)
-{
- struct deinterlace_ctx *ctx = priv;
- struct deinterlace_dev *pcdev = ctx->dev;
-
- ctx->aborting = 1;
-
- dprintk(pcdev, "Aborting task\n");
-
- v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx);
-}
-
static void dma_callback(void *data)
{
struct deinterlace_ctx *curr_ctx = data;
struct deinterlace_dev *pcdev = curr_ctx->dev;
struct vb2_v4l2_buffer *src_vb, *dst_vb;
+ struct deinterlace_q_data *q_data;
- atomic_set(&pcdev->busy, 0);
-
+ pr_err("callback\n");
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
- dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
- dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
- dst_vb->flags |=
- src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
- dst_vb->timecode = src_vb->timecode;
+ v4l2_m2m_buf_copy_metadata(src_vb, dst_vb, true);
+
+ q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ src_vb->sequence = q_data->sequence++;
+ src_vb->field = q_data->field;
+ q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ dst_vb->sequence = q_data->sequence++;
+ dst_vb->field = q_data->field;
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+ atomic_set(&pcdev->busy, 0);
v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx);
dprintk(pcdev, "dma transfers completed.\n");
@@ -221,15 +214,16 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op,
s_height = s_q_data->height;
s_size = s_width * s_height;
- p_in = (dma_addr_t)vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
- p_out = (dma_addr_t)vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf,
- 0);
+ p_in = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ p_out = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
if (!p_in || !p_out) {
v4l2_err(&pcdev->v4l2_dev,
"Acquiring kernel pointers to buffers failed\n");
return;
}
+ ctx->xt->sgl[0].dst_icg = 0;
+ ctx->xt->sgl[0].src_icg = 0;
switch (op) {
case YUV420_DMA_Y_ODD:
ctx->xt->numf = s_height / 2;
@@ -318,11 +312,13 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op,
break;
}
- /* Common parameters for al transfers */
+ /* Common parameters for all transfers */
ctx->xt->frame_size = 1;
ctx->xt->dir = DMA_MEM_TO_MEM;
ctx->xt->src_sgl = false;
+ ctx->xt->src_inc = true;
ctx->xt->dst_sgl = true;
+ ctx->xt->dst_inc = true;
flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
tx = dmadev->device_prep_interleaved_dma(chan, ctx->xt, flags);
@@ -345,6 +341,7 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op,
return;
}
+ if (do_callback)
dma_async_issue_pending(chan);
}
@@ -433,14 +430,14 @@ static int vidioc_querycap(struct file *file, void *priv,
{
strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
- strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", MEM2MEM_NAME);
return 0;
}
static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
{
int i, num;
- struct deinterlace_fmt *fmt;
num = 0;
@@ -457,8 +454,7 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
if (i < NUM_FORMATS) {
/* Format found */
- fmt = &formats[i];
- f->pixelformat = fmt->fourcc;
+ f->pixelformat = formats[i].fourcc;
return 0;
}
@@ -496,15 +492,19 @@ static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
switch (q_data->fmt->fourcc) {
case V4L2_PIX_FMT_YUV420:
- f->fmt.pix.bytesperline = q_data->width * 3 / 2;
+ f->fmt.pix.bytesperline = q_data->width;
break;
case V4L2_PIX_FMT_YUYV:
default:
f->fmt.pix.bytesperline = q_data->width * 2;
+ break;
}
f->fmt.pix.sizeimage = q_data->sizeimage;
f->fmt.pix.colorspace = ctx->colorspace;
+ f->fmt.pix.xfer_func = ctx->xfer_func;
+ f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
+ f->fmt.pix.quantization = ctx->quant;
return 0;
}
@@ -525,13 +525,17 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct deinterlace_fmt *fmt)
{
switch (f->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_YUV420:
- f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+ f->fmt.pix.bytesperline = f->fmt.pix.width;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline * 3 / 2;
break;
case V4L2_PIX_FMT_YUYV:
default:
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ break;
}
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
}
@@ -553,6 +557,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.field != V4L2_FIELD_NONE)
f->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
+ f->fmt.pix.xfer_func = ctx->xfer_func;
+ f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
+ f->fmt.pix.quantization = ctx->quant;
+
return vidioc_try_fmt(f, fmt);
}
@@ -608,13 +616,14 @@ static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
switch (f->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_YUV420:
- f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+ f->fmt.pix.bytesperline = f->fmt.pix.width;
q_data->sizeimage = (q_data->width * q_data->height * 3) / 2;
break;
case V4L2_PIX_FMT_YUYV:
default:
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
q_data->sizeimage = q_data->width * q_data->height * 2;
+ break;
}
dprintk(ctx->dev,
@@ -647,8 +656,12 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
return ret;
ret = vidioc_s_fmt(priv, f);
- if (!ret)
+ if (!ret) {
ctx->colorspace = f->fmt.pix.colorspace;
+ ctx->xfer_func = f->fmt.pix.xfer_func;
+ ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ ctx->quant = f->fmt.pix.quantization;
+ }
return ret;
}
@@ -710,6 +723,7 @@ static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = {
.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
@@ -732,9 +746,8 @@ static int deinterlace_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], struct device *alloc_devs[])
{
- struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
struct deinterlace_q_data *q_data;
- unsigned int size, count = *nbuffers;
+ unsigned int size;
q_data = get_q_data(vq->type);
@@ -745,25 +758,27 @@ static int deinterlace_queue_setup(struct vb2_queue *vq,
case V4L2_PIX_FMT_YUYV:
default:
size = q_data->width * q_data->height * 2;
+ break;
}
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
+
*nplanes = 1;
- *nbuffers = count;
sizes[0] = size;
-
- dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
-
return 0;
}
static int deinterlace_buf_prepare(struct vb2_buffer *vb)
{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct deinterlace_q_data *q_data;
dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
q_data = get_q_data(vb->vb2_queue->type);
+ vbuf->field = q_data->field;
if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
@@ -784,10 +799,37 @@ static void deinterlace_buf_queue(struct vb2_buffer *vb)
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
}
+static int deinterlace_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct deinterlace_q_data *q_data = get_q_data(q->type);
+
+ q_data->sequence = 0;
+ return 0;
+}
+
+static void deinterlace_stop_streaming(struct vb2_queue *q)
+{
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_v4l2_buffer *vbuf;
+
+ for (;;) {
+ pr_err("stop %d\n", V4L2_TYPE_IS_OUTPUT(q->type));
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ if (!vbuf)
+ return;
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ }
+}
+
static const struct vb2_ops deinterlace_qops = {
.queue_setup = deinterlace_queue_setup,
.buf_prepare = deinterlace_buf_prepare,
.buf_queue = deinterlace_buf_queue,
+ .start_streaming = deinterlace_start_streaming,
+ .stop_streaming = deinterlace_stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
@@ -799,7 +841,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &deinterlace_qops;
@@ -818,7 +860,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &deinterlace_qops;
@@ -830,7 +872,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
q_data[V4L2_M2M_DST].width = 640;
q_data[V4L2_M2M_DST].height = 480;
q_data[V4L2_M2M_DST].sizeimage = (640 * 480 * 3) / 2;
- q_data[V4L2_M2M_SRC].field = V4L2_FIELD_INTERLACED_TB;
+ q_data[V4L2_M2M_DST].field = V4L2_FIELD_NONE;
return vb2_queue_init(dst_vq);
}
@@ -912,8 +954,7 @@ static const struct video_device deinterlace_videodev = {
static const struct v4l2_m2m_ops m2m_ops = {
.device_run = deinterlace_device_run,
- .job_ready = deinterlace_job_ready,
- .job_abort = deinterlace_job_abort,
+// .job_ready = deinterlace_job_ready,
};
static int deinterlace_probe(struct platform_device *pdev)
@@ -927,8 +968,8 @@ static int deinterlace_probe(struct platform_device *pdev)
if (!pcdev)
return -ENOMEM;
- spin_lock_init(&pcdev->irqlock);
-
+ dma_set_mask(&pdev->dev, 0xffffffff);
+ dma_set_coherent_mask(&pdev->dev, 0xffffffff);
dma_cap_zero(mask);
dma_cap_set(DMA_INTERLEAVE, mask);
pcdev->dma_chan = dma_request_channel(mask, NULL, pcdev);
@@ -1004,5 +1045,36 @@ static struct platform_driver deinterlace_pdrv = {
.name = MEM2MEM_NAME,
},
};
-module_platform_driver(deinterlace_pdrv);
+//module_platform_driver(deinterlace_pdrv);
+
+static void deinterlace_dev_release(struct device *dev)
+{}
+
+static struct platform_device deinterlace_pdev = {
+ .name = MEM2MEM_NAME,
+ .dev.release = deinterlace_dev_release,
+};
+
+static void __exit deinterlace_exit(void)
+{
+ platform_driver_unregister(&deinterlace_pdrv);
+ platform_device_unregister(&deinterlace_pdev);
+}
+
+static int __init deinterlace_init(void)
+{
+ int ret;
+
+ ret = platform_device_register(&deinterlace_pdev);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&deinterlace_pdrv);
+ if (ret)
+ platform_device_unregister(&deinterlace_pdev);
+
+ return ret;
+}
+module_init(deinterlace_init);
+module_exit(deinterlace_exit);

Privacy Policy