.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * V4L2 deinterlacing support. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2012 Vista Silicon S.L. |
---|
5 | 6 | * Javier Martin <javier.martin@vista-silicon.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License as published by the |
---|
9 | | - * Free Software Foundation; either version 2 of the |
---|
10 | | - * License, or (at your option) any later version |
---|
11 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #include <linux/module.h> |
---|
.. | .. |
---|
41 | 37 | v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) |
---|
42 | 38 | |
---|
43 | 39 | struct deinterlace_fmt { |
---|
44 | | - char *name; |
---|
45 | 40 | u32 fourcc; |
---|
46 | 41 | /* Types the format can be used for */ |
---|
47 | 42 | u32 types; |
---|
.. | .. |
---|
49 | 44 | |
---|
50 | 45 | static struct deinterlace_fmt formats[] = { |
---|
51 | 46 | { |
---|
52 | | - .name = "YUV 4:2:0 Planar", |
---|
53 | 47 | .fourcc = V4L2_PIX_FMT_YUV420, |
---|
54 | 48 | .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, |
---|
55 | 49 | }, |
---|
56 | 50 | { |
---|
57 | | - .name = "YUYV 4:2:2", |
---|
58 | 51 | .fourcc = V4L2_PIX_FMT_YUYV, |
---|
59 | 52 | .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, |
---|
60 | 53 | }, |
---|
.. | .. |
---|
139 | 132 | }; |
---|
140 | 133 | |
---|
141 | 134 | struct deinterlace_ctx { |
---|
| 135 | + struct v4l2_fh fh; |
---|
142 | 136 | struct deinterlace_dev *dev; |
---|
143 | 137 | |
---|
144 | 138 | /* Abort requested by m2m */ |
---|
145 | 139 | int aborting; |
---|
146 | 140 | enum v4l2_colorspace colorspace; |
---|
147 | 141 | dma_cookie_t cookie; |
---|
148 | | - struct v4l2_m2m_ctx *m2m_ctx; |
---|
149 | 142 | struct dma_interleaved_template *xt; |
---|
150 | 143 | }; |
---|
151 | 144 | |
---|
.. | .. |
---|
157 | 150 | struct deinterlace_ctx *ctx = priv; |
---|
158 | 151 | struct deinterlace_dev *pcdev = ctx->dev; |
---|
159 | 152 | |
---|
160 | | - if ((v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) |
---|
161 | | - && (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0) |
---|
162 | | - && (atomic_read(&ctx->dev->busy) == 0)) { |
---|
| 153 | + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0 && |
---|
| 154 | + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0 && |
---|
| 155 | + !atomic_read(&ctx->dev->busy)) { |
---|
163 | 156 | dprintk(pcdev, "Task ready\n"); |
---|
164 | 157 | return 1; |
---|
165 | 158 | } |
---|
.. | .. |
---|
178 | 171 | |
---|
179 | 172 | dprintk(pcdev, "Aborting task\n"); |
---|
180 | 173 | |
---|
181 | | - v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); |
---|
| 174 | + v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx); |
---|
182 | 175 | } |
---|
183 | 176 | |
---|
184 | 177 | static void dma_callback(void *data) |
---|
.. | .. |
---|
189 | 182 | |
---|
190 | 183 | atomic_set(&pcdev->busy, 0); |
---|
191 | 184 | |
---|
192 | | - src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); |
---|
193 | | - dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); |
---|
| 185 | + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); |
---|
| 186 | + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); |
---|
194 | 187 | |
---|
195 | 188 | dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; |
---|
196 | 189 | dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; |
---|
.. | .. |
---|
201 | 194 | v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); |
---|
202 | 195 | v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); |
---|
203 | 196 | |
---|
204 | | - v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); |
---|
| 197 | + v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx); |
---|
205 | 198 | |
---|
206 | 199 | dprintk(pcdev, "dma transfers completed.\n"); |
---|
207 | 200 | } |
---|
.. | .. |
---|
220 | 213 | dma_addr_t p_in, p_out; |
---|
221 | 214 | enum dma_ctrl_flags flags; |
---|
222 | 215 | |
---|
223 | | - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); |
---|
224 | | - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); |
---|
| 216 | + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); |
---|
| 217 | + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); |
---|
225 | 218 | |
---|
226 | 219 | s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); |
---|
227 | 220 | s_width = s_q_data->width; |
---|
.. | .. |
---|
438 | 431 | static int vidioc_querycap(struct file *file, void *priv, |
---|
439 | 432 | struct v4l2_capability *cap) |
---|
440 | 433 | { |
---|
441 | | - strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); |
---|
442 | | - strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); |
---|
443 | | - strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card)); |
---|
444 | | - /* |
---|
445 | | - * This is only a mem-to-mem video device. The capture and output |
---|
446 | | - * device capability flags are left only for backward compatibility |
---|
447 | | - * and are scheduled for removal. |
---|
448 | | - */ |
---|
449 | | - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | |
---|
450 | | - V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; |
---|
451 | | - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
---|
452 | | - |
---|
| 434 | + strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); |
---|
| 435 | + strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); |
---|
| 436 | + strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info)); |
---|
453 | 437 | return 0; |
---|
454 | 438 | } |
---|
455 | 439 | |
---|
.. | .. |
---|
474 | 458 | if (i < NUM_FORMATS) { |
---|
475 | 459 | /* Format found */ |
---|
476 | 460 | fmt = &formats[i]; |
---|
477 | | - strlcpy(f->description, fmt->name, sizeof(f->description)); |
---|
478 | 461 | f->pixelformat = fmt->fourcc; |
---|
479 | 462 | return 0; |
---|
480 | 463 | } |
---|
.. | .. |
---|
500 | 483 | struct vb2_queue *vq; |
---|
501 | 484 | struct deinterlace_q_data *q_data; |
---|
502 | 485 | |
---|
503 | | - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); |
---|
| 486 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
---|
504 | 487 | if (!vq) |
---|
505 | 488 | return -EINVAL; |
---|
506 | 489 | |
---|
.. | .. |
---|
597 | 580 | struct deinterlace_q_data *q_data; |
---|
598 | 581 | struct vb2_queue *vq; |
---|
599 | 582 | |
---|
600 | | - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); |
---|
| 583 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
---|
601 | 584 | if (!vq) |
---|
602 | 585 | return -EINVAL; |
---|
603 | 586 | |
---|
.. | .. |
---|
670 | 653 | return ret; |
---|
671 | 654 | } |
---|
672 | 655 | |
---|
673 | | -static int vidioc_reqbufs(struct file *file, void *priv, |
---|
674 | | - struct v4l2_requestbuffers *reqbufs) |
---|
675 | | -{ |
---|
676 | | - struct deinterlace_ctx *ctx = priv; |
---|
677 | | - |
---|
678 | | - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); |
---|
679 | | -} |
---|
680 | | - |
---|
681 | | -static int vidioc_querybuf(struct file *file, void *priv, |
---|
682 | | - struct v4l2_buffer *buf) |
---|
683 | | -{ |
---|
684 | | - struct deinterlace_ctx *ctx = priv; |
---|
685 | | - |
---|
686 | | - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); |
---|
687 | | -} |
---|
688 | | - |
---|
689 | | -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) |
---|
690 | | -{ |
---|
691 | | - struct deinterlace_ctx *ctx = priv; |
---|
692 | | - |
---|
693 | | - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); |
---|
694 | | -} |
---|
695 | | - |
---|
696 | | -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) |
---|
697 | | -{ |
---|
698 | | - struct deinterlace_ctx *ctx = priv; |
---|
699 | | - |
---|
700 | | - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); |
---|
701 | | -} |
---|
702 | | - |
---|
703 | 656 | static int vidioc_streamon(struct file *file, void *priv, |
---|
704 | 657 | enum v4l2_buf_type type) |
---|
705 | 658 | { |
---|
.. | .. |
---|
740 | 693 | return -EINVAL; |
---|
741 | 694 | } |
---|
742 | 695 | |
---|
743 | | - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); |
---|
744 | | -} |
---|
745 | | - |
---|
746 | | -static int vidioc_streamoff(struct file *file, void *priv, |
---|
747 | | - enum v4l2_buf_type type) |
---|
748 | | -{ |
---|
749 | | - struct deinterlace_ctx *ctx = priv; |
---|
750 | | - |
---|
751 | | - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); |
---|
| 696 | + return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type); |
---|
752 | 697 | } |
---|
753 | 698 | |
---|
754 | 699 | static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = { |
---|
.. | .. |
---|
764 | 709 | .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, |
---|
765 | 710 | .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, |
---|
766 | 711 | |
---|
767 | | - .vidioc_reqbufs = vidioc_reqbufs, |
---|
768 | | - .vidioc_querybuf = vidioc_querybuf, |
---|
769 | | - |
---|
770 | | - .vidioc_qbuf = vidioc_qbuf, |
---|
771 | | - .vidioc_dqbuf = vidioc_dqbuf, |
---|
| 712 | + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
---|
| 713 | + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
---|
| 714 | + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, |
---|
| 715 | + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, |
---|
| 716 | + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, |
---|
| 717 | + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, |
---|
772 | 718 | |
---|
773 | 719 | .vidioc_streamon = vidioc_streamon, |
---|
774 | | - .vidioc_streamoff = vidioc_streamoff, |
---|
| 720 | + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
---|
775 | 721 | }; |
---|
776 | 722 | |
---|
777 | 723 | |
---|
.. | .. |
---|
835 | 781 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
---|
836 | 782 | struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
---|
837 | 783 | |
---|
838 | | - v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); |
---|
| 784 | + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); |
---|
839 | 785 | } |
---|
840 | 786 | |
---|
841 | 787 | static const struct vb2_ops deinterlace_qops = { |
---|
.. | .. |
---|
853 | 799 | int ret; |
---|
854 | 800 | |
---|
855 | 801 | src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
---|
856 | | - src_vq->io_modes = VB2_MMAP | VB2_USERPTR; |
---|
| 802 | + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; |
---|
857 | 803 | src_vq->drv_priv = ctx; |
---|
858 | 804 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
---|
859 | 805 | src_vq->ops = &deinterlace_qops; |
---|
.. | .. |
---|
872 | 818 | return ret; |
---|
873 | 819 | |
---|
874 | 820 | dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
---|
875 | | - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; |
---|
| 821 | + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; |
---|
876 | 822 | dst_vq->drv_priv = ctx; |
---|
877 | 823 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
---|
878 | 824 | dst_vq->ops = &deinterlace_qops; |
---|
.. | .. |
---|
901 | 847 | if (!ctx) |
---|
902 | 848 | return -ENOMEM; |
---|
903 | 849 | |
---|
904 | | - file->private_data = ctx; |
---|
| 850 | + v4l2_fh_init(&ctx->fh, video_devdata(file)); |
---|
| 851 | + file->private_data = &ctx->fh; |
---|
905 | 852 | ctx->dev = pcdev; |
---|
906 | 853 | |
---|
907 | | - ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); |
---|
908 | | - if (IS_ERR(ctx->m2m_ctx)) { |
---|
909 | | - int ret = PTR_ERR(ctx->m2m_ctx); |
---|
| 854 | + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); |
---|
| 855 | + if (IS_ERR(ctx->fh.m2m_ctx)) { |
---|
| 856 | + int ret = PTR_ERR(ctx->fh.m2m_ctx); |
---|
910 | 857 | |
---|
911 | 858 | kfree(ctx); |
---|
912 | 859 | return ret; |
---|
.. | .. |
---|
920 | 867 | } |
---|
921 | 868 | |
---|
922 | 869 | ctx->colorspace = V4L2_COLORSPACE_REC709; |
---|
| 870 | + v4l2_fh_add(&ctx->fh); |
---|
923 | 871 | |
---|
924 | | - dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); |
---|
| 872 | + dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", |
---|
| 873 | + ctx, ctx->fh.m2m_ctx); |
---|
925 | 874 | |
---|
926 | 875 | return 0; |
---|
927 | 876 | } |
---|
.. | .. |
---|
933 | 882 | |
---|
934 | 883 | dprintk(pcdev, "Releasing instance %p\n", ctx); |
---|
935 | 884 | |
---|
936 | | - v4l2_m2m_ctx_release(ctx->m2m_ctx); |
---|
| 885 | + v4l2_fh_del(&ctx->fh); |
---|
| 886 | + v4l2_fh_exit(&ctx->fh); |
---|
| 887 | + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
---|
937 | 888 | kfree(ctx->xt); |
---|
938 | 889 | kfree(ctx); |
---|
939 | 890 | |
---|
940 | 891 | return 0; |
---|
941 | 892 | } |
---|
942 | 893 | |
---|
943 | | -static __poll_t deinterlace_poll(struct file *file, |
---|
944 | | - struct poll_table_struct *wait) |
---|
945 | | -{ |
---|
946 | | - struct deinterlace_ctx *ctx = file->private_data; |
---|
947 | | - __poll_t ret; |
---|
948 | | - |
---|
949 | | - mutex_lock(&ctx->dev->dev_mutex); |
---|
950 | | - ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); |
---|
951 | | - mutex_unlock(&ctx->dev->dev_mutex); |
---|
952 | | - |
---|
953 | | - return ret; |
---|
954 | | -} |
---|
955 | | - |
---|
956 | | -static int deinterlace_mmap(struct file *file, struct vm_area_struct *vma) |
---|
957 | | -{ |
---|
958 | | - struct deinterlace_ctx *ctx = file->private_data; |
---|
959 | | - |
---|
960 | | - return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); |
---|
961 | | -} |
---|
962 | | - |
---|
963 | 894 | static const struct v4l2_file_operations deinterlace_fops = { |
---|
964 | 895 | .owner = THIS_MODULE, |
---|
965 | 896 | .open = deinterlace_open, |
---|
966 | 897 | .release = deinterlace_release, |
---|
967 | | - .poll = deinterlace_poll, |
---|
| 898 | + .poll = v4l2_m2m_fop_poll, |
---|
968 | 899 | .unlocked_ioctl = video_ioctl2, |
---|
969 | | - .mmap = deinterlace_mmap, |
---|
| 900 | + .mmap = v4l2_m2m_fop_mmap, |
---|
970 | 901 | }; |
---|
971 | 902 | |
---|
972 | 903 | static const struct video_device deinterlace_videodev = { |
---|
.. | .. |
---|
976 | 907 | .minor = -1, |
---|
977 | 908 | .release = video_device_release_empty, |
---|
978 | 909 | .vfl_dir = VFL_DIR_M2M, |
---|
| 910 | + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, |
---|
979 | 911 | }; |
---|
980 | 912 | |
---|
981 | 913 | static const struct v4l2_m2m_ops m2m_ops = { |
---|
.. | .. |
---|
1021 | 953 | vfd->lock = &pcdev->dev_mutex; |
---|
1022 | 954 | vfd->v4l2_dev = &pcdev->v4l2_dev; |
---|
1023 | 955 | |
---|
1024 | | - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); |
---|
| 956 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); |
---|
1025 | 957 | if (ret) { |
---|
1026 | 958 | v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); |
---|
1027 | 959 | goto unreg_dev; |
---|