media: vicodec: Add support for 4 planes formats
[linux-2.6-block.git] / drivers / media / platform / vicodec / vicodec-core.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * A virtual codec example device.
4  *
5  * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6  *
7  * This is a virtual codec device driver for testing the codec framework.
8  * It simulates a device that uses memory buffers for both source and
9  * destination and encodes or decodes the data.
10  */
11
12 #include <linux/module.h>
13 #include <linux/delay.h>
14 #include <linux/fs.h>
15 #include <linux/sched.h>
16 #include <linux/slab.h>
17
18 #include <linux/platform_device.h>
19 #include <media/v4l2-mem2mem.h>
20 #include <media/v4l2-device.h>
21 #include <media/v4l2-ioctl.h>
22 #include <media/v4l2-ctrls.h>
23 #include <media/v4l2-event.h>
24 #include <media/videobuf2-vmalloc.h>
25
26 #include "codec-v4l2-fwht.h"
27
28 MODULE_DESCRIPTION("Virtual codec device");
29 MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
30 MODULE_LICENSE("GPL v2");
31
32 static bool multiplanar;
33 module_param(multiplanar, bool, 0444);
34 MODULE_PARM_DESC(multiplanar,
35                  " use multi-planar API instead of single-planar API");
36
37 static unsigned int debug;
38 module_param(debug, uint, 0644);
39 MODULE_PARM_DESC(debug, " activates debug info");
40
41 #define VICODEC_NAME            "vicodec"
42 #define MAX_WIDTH               4096U
43 #define MIN_WIDTH               640U
44 #define MAX_HEIGHT              2160U
45 #define MIN_HEIGHT              360U
46
47 #define dprintk(dev, fmt, arg...) \
48         v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
49
50
51 struct pixfmt_info {
52         u32 id;
53         unsigned int bytesperline_mult;
54         unsigned int sizeimage_mult;
55         unsigned int sizeimage_div;
56         unsigned int luma_step;
57         unsigned int chroma_step;
58         /* Chroma plane subsampling */
59         unsigned int width_div;
60         unsigned int height_div;
61 };
62
63 static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
64         V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0
65 };
66
67 static void vicodec_dev_release(struct device *dev)
68 {
69 }
70
71 static struct platform_device vicodec_pdev = {
72         .name           = VICODEC_NAME,
73         .dev.release    = vicodec_dev_release,
74 };
75
76 /* Per-queue, driver-specific private data */
77 struct vicodec_q_data {
78         unsigned int            width;
79         unsigned int            height;
80         unsigned int            sizeimage;
81         unsigned int            sequence;
82         const struct v4l2_fwht_pixfmt_info *info;
83 };
84
85 enum {
86         V4L2_M2M_SRC = 0,
87         V4L2_M2M_DST = 1,
88 };
89
90 struct vicodec_dev {
91         struct v4l2_device      v4l2_dev;
92         struct video_device     enc_vfd;
93         struct video_device     dec_vfd;
94 #ifdef CONFIG_MEDIA_CONTROLLER
95         struct media_device     mdev;
96 #endif
97
98         struct mutex            enc_mutex;
99         struct mutex            dec_mutex;
100         spinlock_t              enc_lock;
101         spinlock_t              dec_lock;
102
103         struct v4l2_m2m_dev     *enc_dev;
104         struct v4l2_m2m_dev     *dec_dev;
105 };
106
107 struct vicodec_ctx {
108         struct v4l2_fh          fh;
109         struct vicodec_dev      *dev;
110         bool                    is_enc;
111         spinlock_t              *lock;
112
113         struct v4l2_ctrl_handler hdl;
114
115         struct vb2_v4l2_buffer *last_src_buf;
116         struct vb2_v4l2_buffer *last_dst_buf;
117
118         /* Source and destination queue data */
119         struct vicodec_q_data   q_data[2];
120         struct v4l2_fwht_state  state;
121
122         u32                     cur_buf_offset;
123         u32                     comp_max_size;
124         u32                     comp_size;
125         u32                     comp_magic_cnt;
126         u32                     comp_frame_size;
127         bool                    comp_has_frame;
128         bool                    comp_has_next_frame;
129 };
130
131 static inline struct vicodec_ctx *file2ctx(struct file *file)
132 {
133         return container_of(file->private_data, struct vicodec_ctx, fh);
134 }
135
136 static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
137                                          enum v4l2_buf_type type)
138 {
139         switch (type) {
140         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
141         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
142                 return &ctx->q_data[V4L2_M2M_SRC];
143         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
144         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
145                 return &ctx->q_data[V4L2_M2M_DST];
146         default:
147                 WARN_ON(1);
148                 break;
149         }
150         return NULL;
151 }
152
153 static int device_process(struct vicodec_ctx *ctx,
154                           struct vb2_v4l2_buffer *in_vb,
155                           struct vb2_v4l2_buffer *out_vb)
156 {
157         struct vicodec_dev *dev = ctx->dev;
158         struct vicodec_q_data *q_cap;
159         struct v4l2_fwht_state *state = &ctx->state;
160         u8 *p_in, *p_out;
161         int ret;
162
163         q_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
164         if (ctx->is_enc)
165                 p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
166         else
167                 p_in = state->compressed_frame;
168         p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
169         if (!p_in || !p_out) {
170                 v4l2_err(&dev->v4l2_dev,
171                          "Acquiring kernel pointers to buffers failed\n");
172                 return -EFAULT;
173         }
174
175         if (ctx->is_enc) {
176                 struct vicodec_q_data *q_out;
177
178                 q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
179                 state->info = q_out->info;
180                 ret = v4l2_fwht_encode(state, p_in, p_out);
181                 if (ret < 0)
182                         return ret;
183                 vb2_set_plane_payload(&out_vb->vb2_buf, 0, ret);
184         } else {
185                 state->info = q_cap->info;
186                 ret = v4l2_fwht_decode(state, p_in, p_out);
187                 if (ret < 0)
188                         return ret;
189                 vb2_set_plane_payload(&out_vb->vb2_buf, 0, q_cap->sizeimage);
190         }
191
192         out_vb->sequence = q_cap->sequence++;
193         out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
194
195         if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
196                 out_vb->timecode = in_vb->timecode;
197         out_vb->field = in_vb->field;
198         out_vb->flags &= ~V4L2_BUF_FLAG_LAST;
199         out_vb->flags |= in_vb->flags &
200                 (V4L2_BUF_FLAG_TIMECODE |
201                  V4L2_BUF_FLAG_KEYFRAME |
202                  V4L2_BUF_FLAG_PFRAME |
203                  V4L2_BUF_FLAG_BFRAME |
204                  V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
205
206         return 0;
207 }
208
209 /*
210  * mem2mem callbacks
211  */
212
213 /* device_run() - prepares and starts the device */
214 static void device_run(void *priv)
215 {
216         static const struct v4l2_event eos_event = {
217                 .type = V4L2_EVENT_EOS
218         };
219         struct vicodec_ctx *ctx = priv;
220         struct vicodec_dev *dev = ctx->dev;
221         struct vb2_v4l2_buffer *src_buf, *dst_buf;
222         struct vicodec_q_data *q_out;
223         u32 state;
224
225         src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
226         dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
227         q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
228
229         state = VB2_BUF_STATE_DONE;
230         if (device_process(ctx, src_buf, dst_buf))
231                 state = VB2_BUF_STATE_ERROR;
232         ctx->last_dst_buf = dst_buf;
233
234         spin_lock(ctx->lock);
235         if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
236                 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
237                 v4l2_event_queue_fh(&ctx->fh, &eos_event);
238         }
239         if (ctx->is_enc) {
240                 src_buf->sequence = q_out->sequence++;
241                 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
242                 v4l2_m2m_buf_done(src_buf, state);
243         } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) {
244                 src_buf->sequence = q_out->sequence++;
245                 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
246                 v4l2_m2m_buf_done(src_buf, state);
247                 ctx->cur_buf_offset = 0;
248                 ctx->comp_has_next_frame = false;
249         }
250         v4l2_m2m_buf_done(dst_buf, state);
251         ctx->comp_size = 0;
252         ctx->comp_magic_cnt = 0;
253         ctx->comp_has_frame = false;
254         spin_unlock(ctx->lock);
255
256         if (ctx->is_enc)
257                 v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
258         else
259                 v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
260 }
261
262 static void job_remove_out_buf(struct vicodec_ctx *ctx, u32 state)
263 {
264         struct vb2_v4l2_buffer *src_buf;
265         struct vicodec_q_data *q_out;
266
267         q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
268         spin_lock(ctx->lock);
269         src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
270         src_buf->sequence = q_out->sequence++;
271         v4l2_m2m_buf_done(src_buf, state);
272         ctx->cur_buf_offset = 0;
273         spin_unlock(ctx->lock);
274 }
275
276 static int job_ready(void *priv)
277 {
278         static const u8 magic[] = {
279                 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
280         };
281         struct vicodec_ctx *ctx = priv;
282         struct vb2_v4l2_buffer *src_buf;
283         u8 *p_out;
284         u8 *p;
285         u32 sz;
286         u32 state;
287
288         if (ctx->is_enc || ctx->comp_has_frame)
289                 return 1;
290
291 restart:
292         ctx->comp_has_next_frame = false;
293         src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
294         if (!src_buf)
295                 return 0;
296         p_out = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
297         sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
298         p = p_out + ctx->cur_buf_offset;
299
300         state = VB2_BUF_STATE_DONE;
301
302         if (!ctx->comp_size) {
303                 state = VB2_BUF_STATE_ERROR;
304                 for (; p < p_out + sz; p++) {
305                         u32 copy;
306
307                         p = memchr(p, magic[ctx->comp_magic_cnt], sz);
308                         if (!p) {
309                                 ctx->comp_magic_cnt = 0;
310                                 break;
311                         }
312                         copy = sizeof(magic) - ctx->comp_magic_cnt;
313                         if (p_out + sz - p < copy)
314                                 copy = p_out + sz - p;
315                         memcpy(ctx->state.compressed_frame + ctx->comp_magic_cnt,
316                                p, copy);
317                         ctx->comp_magic_cnt += copy;
318                         if (!memcmp(ctx->state.compressed_frame, magic,
319                                     ctx->comp_magic_cnt)) {
320                                 p += copy;
321                                 state = VB2_BUF_STATE_DONE;
322                                 break;
323                         }
324                         ctx->comp_magic_cnt = 0;
325                 }
326                 if (ctx->comp_magic_cnt < sizeof(magic)) {
327                         job_remove_out_buf(ctx, state);
328                         goto restart;
329                 }
330                 ctx->comp_size = sizeof(magic);
331         }
332         if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
333                 struct fwht_cframe_hdr *p_hdr =
334                         (struct fwht_cframe_hdr *)ctx->state.compressed_frame;
335                 u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->comp_size;
336
337                 if (copy > p_out + sz - p)
338                         copy = p_out + sz - p;
339                 memcpy(ctx->state.compressed_frame + ctx->comp_size,
340                        p, copy);
341                 p += copy;
342                 ctx->comp_size += copy;
343                 if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
344                         job_remove_out_buf(ctx, state);
345                         goto restart;
346                 }
347                 ctx->comp_frame_size = ntohl(p_hdr->size) + sizeof(*p_hdr);
348                 if (ctx->comp_frame_size > ctx->comp_max_size)
349                         ctx->comp_frame_size = ctx->comp_max_size;
350         }
351         if (ctx->comp_size < ctx->comp_frame_size) {
352                 u32 copy = ctx->comp_frame_size - ctx->comp_size;
353
354                 if (copy > p_out + sz - p)
355                         copy = p_out + sz - p;
356                 memcpy(ctx->state.compressed_frame + ctx->comp_size,
357                        p, copy);
358                 p += copy;
359                 ctx->comp_size += copy;
360                 if (ctx->comp_size < ctx->comp_frame_size) {
361                         job_remove_out_buf(ctx, state);
362                         goto restart;
363                 }
364         }
365         ctx->cur_buf_offset = p - p_out;
366         ctx->comp_has_frame = true;
367         ctx->comp_has_next_frame = false;
368         if (sz - ctx->cur_buf_offset >= sizeof(struct fwht_cframe_hdr)) {
369                 struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
370                 u32 frame_size = ntohl(p_hdr->size);
371                 u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
372
373                 if (!memcmp(p, magic, sizeof(magic)))
374                         ctx->comp_has_next_frame = remaining >= frame_size;
375         }
376         return 1;
377 }
378
379 /*
380  * video ioctls
381  */
382
383 static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
384 {
385         const struct v4l2_fwht_pixfmt_info *info =
386                 v4l2_fwht_find_pixfmt(fmt);
387
388         if (!info)
389                 info = v4l2_fwht_get_pixfmt(0);
390         return info;
391 }
392
393 static int vidioc_querycap(struct file *file, void *priv,
394                            struct v4l2_capability *cap)
395 {
396         strncpy(cap->driver, VICODEC_NAME, sizeof(cap->driver) - 1);
397         strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1);
398         snprintf(cap->bus_info, sizeof(cap->bus_info),
399                         "platform:%s", VICODEC_NAME);
400         return 0;
401 }
402
403 static int enum_fmt(struct v4l2_fmtdesc *f, bool is_enc, bool is_out)
404 {
405         bool is_uncomp = (is_enc && is_out) || (!is_enc && !is_out);
406
407         if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
408                 return -EINVAL;
409         if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
410                 return -EINVAL;
411
412         if (is_uncomp) {
413                 const struct v4l2_fwht_pixfmt_info *info =
414                         v4l2_fwht_get_pixfmt(f->index);
415
416                 if (!info)
417                         return -EINVAL;
418                 f->pixelformat = info->id;
419         } else {
420                 if (f->index)
421                         return -EINVAL;
422                 f->pixelformat = V4L2_PIX_FMT_FWHT;
423         }
424         return 0;
425 }
426
427 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
428                                    struct v4l2_fmtdesc *f)
429 {
430         struct vicodec_ctx *ctx = file2ctx(file);
431
432         return enum_fmt(f, ctx->is_enc, false);
433 }
434
435 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
436                                    struct v4l2_fmtdesc *f)
437 {
438         struct vicodec_ctx *ctx = file2ctx(file);
439
440         return enum_fmt(f, ctx->is_enc, true);
441 }
442
443 static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
444 {
445         struct vb2_queue *vq;
446         struct vicodec_q_data *q_data;
447         struct v4l2_pix_format_mplane *pix_mp;
448         struct v4l2_pix_format *pix;
449         const struct v4l2_fwht_pixfmt_info *info;
450
451         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
452         if (!vq)
453                 return -EINVAL;
454
455         q_data = get_q_data(ctx, f->type);
456         info = q_data->info;
457
458         switch (f->type) {
459         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
460         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
461                 if (multiplanar)
462                         return -EINVAL;
463                 pix = &f->fmt.pix;
464                 pix->width = q_data->width;
465                 pix->height = q_data->height;
466                 pix->field = V4L2_FIELD_NONE;
467                 pix->pixelformat = info->id;
468                 pix->bytesperline = q_data->width * info->bytesperline_mult;
469                 pix->sizeimage = q_data->sizeimage;
470                 pix->colorspace = ctx->state.colorspace;
471                 pix->xfer_func = ctx->state.xfer_func;
472                 pix->ycbcr_enc = ctx->state.ycbcr_enc;
473                 pix->quantization = ctx->state.quantization;
474                 break;
475
476         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
477         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
478                 if (!multiplanar)
479                         return -EINVAL;
480                 pix_mp = &f->fmt.pix_mp;
481                 pix_mp->width = q_data->width;
482                 pix_mp->height = q_data->height;
483                 pix_mp->field = V4L2_FIELD_NONE;
484                 pix_mp->pixelformat = info->id;
485                 pix_mp->num_planes = 1;
486                 pix_mp->plane_fmt[0].bytesperline =
487                                 q_data->width * info->bytesperline_mult;
488                 pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
489                 pix_mp->colorspace = ctx->state.colorspace;
490                 pix_mp->xfer_func = ctx->state.xfer_func;
491                 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
492                 pix_mp->quantization = ctx->state.quantization;
493                 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
494                 memset(pix_mp->plane_fmt[0].reserved, 0,
495                        sizeof(pix_mp->plane_fmt[0].reserved));
496                 break;
497         default:
498                 return -EINVAL;
499         }
500         return 0;
501 }
502
503 static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
504                                 struct v4l2_format *f)
505 {
506         return vidioc_g_fmt(file2ctx(file), f);
507 }
508
509 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
510                                 struct v4l2_format *f)
511 {
512         return vidioc_g_fmt(file2ctx(file), f);
513 }
514
515 static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
516 {
517         struct v4l2_pix_format_mplane *pix_mp;
518         struct v4l2_pix_format *pix;
519         struct v4l2_plane_pix_format *plane;
520         const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht;
521
522         switch (f->type) {
523         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
524         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
525                 pix = &f->fmt.pix;
526                 if (pix->pixelformat != V4L2_PIX_FMT_FWHT)
527                         info = find_fmt(pix->pixelformat);
528                 pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH) & ~7;
529                 pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT) & ~7;
530                 pix->field = V4L2_FIELD_NONE;
531                 pix->bytesperline =
532                         pix->width * info->bytesperline_mult;
533                 pix->sizeimage = pix->width * pix->height *
534                         info->sizeimage_mult / info->sizeimage_div;
535                 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
536                         pix->sizeimage += sizeof(struct fwht_cframe_hdr);
537                 break;
538         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
539         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
540                 pix_mp = &f->fmt.pix_mp;
541                 plane = pix_mp->plane_fmt;
542                 if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT)
543                         info = find_fmt(pix_mp->pixelformat);
544                 pix_mp->num_planes = 1;
545                 pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH) & ~7;
546                 pix_mp->height =
547                         clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT) & ~7;
548                 pix_mp->field = V4L2_FIELD_NONE;
549                 plane->bytesperline =
550                         pix_mp->width * info->bytesperline_mult;
551                 plane->sizeimage = pix_mp->width * pix_mp->height *
552                         info->sizeimage_mult / info->sizeimage_div;
553                 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
554                         plane->sizeimage += sizeof(struct fwht_cframe_hdr);
555                 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
556                 memset(plane->reserved, 0, sizeof(plane->reserved));
557                 break;
558         default:
559                 return -EINVAL;
560         }
561
562         return 0;
563 }
564
565 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
566                                   struct v4l2_format *f)
567 {
568         struct vicodec_ctx *ctx = file2ctx(file);
569         struct v4l2_pix_format_mplane *pix_mp;
570         struct v4l2_pix_format *pix;
571
572         switch (f->type) {
573         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
574                 if (multiplanar)
575                         return -EINVAL;
576                 pix = &f->fmt.pix;
577                 pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
578                                    find_fmt(f->fmt.pix.pixelformat)->id;
579                 pix->colorspace = ctx->state.colorspace;
580                 pix->xfer_func = ctx->state.xfer_func;
581                 pix->ycbcr_enc = ctx->state.ycbcr_enc;
582                 pix->quantization = ctx->state.quantization;
583                 break;
584         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
585                 if (!multiplanar)
586                         return -EINVAL;
587                 pix_mp = &f->fmt.pix_mp;
588                 pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
589                                       find_fmt(pix_mp->pixelformat)->id;
590                 pix_mp->colorspace = ctx->state.colorspace;
591                 pix_mp->xfer_func = ctx->state.xfer_func;
592                 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
593                 pix_mp->quantization = ctx->state.quantization;
594                 break;
595         default:
596                 return -EINVAL;
597         }
598
599         return vidioc_try_fmt(ctx, f);
600 }
601
602 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
603                                   struct v4l2_format *f)
604 {
605         struct vicodec_ctx *ctx = file2ctx(file);
606         struct v4l2_pix_format_mplane *pix_mp;
607         struct v4l2_pix_format *pix;
608
609         switch (f->type) {
610         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
611                 if (multiplanar)
612                         return -EINVAL;
613                 pix = &f->fmt.pix;
614                 pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
615                                    find_fmt(pix->pixelformat)->id;
616                 if (!pix->colorspace)
617                         pix->colorspace = V4L2_COLORSPACE_REC709;
618                 break;
619         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
620                 if (!multiplanar)
621                         return -EINVAL;
622                 pix_mp = &f->fmt.pix_mp;
623                 pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
624                                       find_fmt(pix_mp->pixelformat)->id;
625                 if (!pix_mp->colorspace)
626                         pix_mp->colorspace = V4L2_COLORSPACE_REC709;
627                 break;
628         default:
629                 return -EINVAL;
630         }
631
632         return vidioc_try_fmt(ctx, f);
633 }
634
635 static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
636 {
637         struct vicodec_q_data *q_data;
638         struct vb2_queue *vq;
639         bool fmt_changed = true;
640         struct v4l2_pix_format_mplane *pix_mp;
641         struct v4l2_pix_format *pix;
642
643         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
644         if (!vq)
645                 return -EINVAL;
646
647         q_data = get_q_data(ctx, f->type);
648         if (!q_data)
649                 return -EINVAL;
650
651         switch (f->type) {
652         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
653         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
654                 pix = &f->fmt.pix;
655                 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
656                         fmt_changed =
657                                 q_data->info->id != pix->pixelformat ||
658                                 q_data->width != pix->width ||
659                                 q_data->height != pix->height;
660
661                 if (vb2_is_busy(vq) && fmt_changed)
662                         return -EBUSY;
663
664                 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
665                         q_data->info = &pixfmt_fwht;
666                 else
667                         q_data->info = find_fmt(pix->pixelformat);
668                 q_data->width = pix->width;
669                 q_data->height = pix->height;
670                 q_data->sizeimage = pix->sizeimage;
671                 break;
672         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
673         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
674                 pix_mp = &f->fmt.pix_mp;
675                 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
676                         fmt_changed =
677                                 q_data->info->id != pix_mp->pixelformat ||
678                                 q_data->width != pix_mp->width ||
679                                 q_data->height != pix_mp->height;
680
681                 if (vb2_is_busy(vq) && fmt_changed)
682                         return -EBUSY;
683
684                 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
685                         q_data->info = &pixfmt_fwht;
686                 else
687                         q_data->info = find_fmt(pix_mp->pixelformat);
688                 q_data->width = pix_mp->width;
689                 q_data->height = pix_mp->height;
690                 q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
691                 break;
692         default:
693                 return -EINVAL;
694         }
695
696         dprintk(ctx->dev,
697                 "Setting format for type %d, wxh: %dx%d, fourcc: %08x\n",
698                 f->type, q_data->width, q_data->height, q_data->info->id);
699
700         return 0;
701 }
702
703 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
704                                 struct v4l2_format *f)
705 {
706         int ret;
707
708         ret = vidioc_try_fmt_vid_cap(file, priv, f);
709         if (ret)
710                 return ret;
711
712         return vidioc_s_fmt(file2ctx(file), f);
713 }
714
715 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
716                                 struct v4l2_format *f)
717 {
718         struct vicodec_ctx *ctx = file2ctx(file);
719         struct v4l2_pix_format_mplane *pix_mp;
720         struct v4l2_pix_format *pix;
721         int ret;
722
723         ret = vidioc_try_fmt_vid_out(file, priv, f);
724         if (ret)
725                 return ret;
726
727         ret = vidioc_s_fmt(file2ctx(file), f);
728         if (!ret) {
729                 switch (f->type) {
730                 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
731                 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
732                         pix = &f->fmt.pix;
733                         ctx->state.colorspace = pix->colorspace;
734                         ctx->state.xfer_func = pix->xfer_func;
735                         ctx->state.ycbcr_enc = pix->ycbcr_enc;
736                         ctx->state.quantization = pix->quantization;
737                         break;
738                 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
739                 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
740                         pix_mp = &f->fmt.pix_mp;
741                         ctx->state.colorspace = pix_mp->colorspace;
742                         ctx->state.xfer_func = pix_mp->xfer_func;
743                         ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
744                         ctx->state.quantization = pix_mp->quantization;
745                         break;
746                 default:
747                         break;
748                 }
749         }
750         return ret;
751 }
752
753 static void vicodec_mark_last_buf(struct vicodec_ctx *ctx)
754 {
755         static const struct v4l2_event eos_event = {
756                 .type = V4L2_EVENT_EOS
757         };
758
759         spin_lock(ctx->lock);
760         ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
761         if (!ctx->last_src_buf && ctx->last_dst_buf) {
762                 ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
763                 v4l2_event_queue_fh(&ctx->fh, &eos_event);
764         }
765         spin_unlock(ctx->lock);
766 }
767
768 static int vicodec_try_encoder_cmd(struct file *file, void *fh,
769                                 struct v4l2_encoder_cmd *ec)
770 {
771         if (ec->cmd != V4L2_ENC_CMD_STOP)
772                 return -EINVAL;
773
774         if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
775                 return -EINVAL;
776
777         return 0;
778 }
779
780 static int vicodec_encoder_cmd(struct file *file, void *fh,
781                             struct v4l2_encoder_cmd *ec)
782 {
783         struct vicodec_ctx *ctx = file2ctx(file);
784         int ret;
785
786         ret = vicodec_try_encoder_cmd(file, fh, ec);
787         if (ret < 0)
788                 return ret;
789
790         vicodec_mark_last_buf(ctx);
791         return 0;
792 }
793
794 static int vicodec_try_decoder_cmd(struct file *file, void *fh,
795                                 struct v4l2_decoder_cmd *dc)
796 {
797         if (dc->cmd != V4L2_DEC_CMD_STOP)
798                 return -EINVAL;
799
800         if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
801                 return -EINVAL;
802
803         if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
804                 return -EINVAL;
805
806         return 0;
807 }
808
809 static int vicodec_decoder_cmd(struct file *file, void *fh,
810                             struct v4l2_decoder_cmd *dc)
811 {
812         struct vicodec_ctx *ctx = file2ctx(file);
813         int ret;
814
815         ret = vicodec_try_decoder_cmd(file, fh, dc);
816         if (ret < 0)
817                 return ret;
818
819         vicodec_mark_last_buf(ctx);
820         return 0;
821 }
822
823 static int vicodec_enum_framesizes(struct file *file, void *fh,
824                                    struct v4l2_frmsizeenum *fsize)
825 {
826         switch (fsize->pixel_format) {
827         case V4L2_PIX_FMT_FWHT:
828                 break;
829         default:
830                 if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
831                         break;
832                 return -EINVAL;
833         }
834
835         if (fsize->index)
836                 return -EINVAL;
837
838         fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
839
840         fsize->stepwise.min_width = MIN_WIDTH;
841         fsize->stepwise.max_width = MAX_WIDTH;
842         fsize->stepwise.step_width = 8;
843         fsize->stepwise.min_height = MIN_HEIGHT;
844         fsize->stepwise.max_height = MAX_HEIGHT;
845         fsize->stepwise.step_height = 8;
846
847         return 0;
848 }
849
850 static int vicodec_subscribe_event(struct v4l2_fh *fh,
851                                 const struct v4l2_event_subscription *sub)
852 {
853         switch (sub->type) {
854         case V4L2_EVENT_EOS:
855                 return v4l2_event_subscribe(fh, sub, 0, NULL);
856         default:
857                 return v4l2_ctrl_subscribe_event(fh, sub);
858         }
859 }
860
861 static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
862         .vidioc_querycap        = vidioc_querycap,
863
864         .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
865         .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
866         .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
867         .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
868
869         .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
870         .vidioc_g_fmt_vid_cap_mplane    = vidioc_g_fmt_vid_cap,
871         .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap,
872         .vidioc_s_fmt_vid_cap_mplane    = vidioc_s_fmt_vid_cap,
873
874         .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
875         .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
876         .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
877         .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
878
879         .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
880         .vidioc_g_fmt_vid_out_mplane    = vidioc_g_fmt_vid_out,
881         .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out,
882         .vidioc_s_fmt_vid_out_mplane    = vidioc_s_fmt_vid_out,
883
884         .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
885         .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
886         .vidioc_qbuf            = v4l2_m2m_ioctl_qbuf,
887         .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
888         .vidioc_prepare_buf     = v4l2_m2m_ioctl_prepare_buf,
889         .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
890         .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
891
892         .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
893         .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
894
895         .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd,
896         .vidioc_encoder_cmd     = vicodec_encoder_cmd,
897         .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd,
898         .vidioc_decoder_cmd     = vicodec_decoder_cmd,
899         .vidioc_enum_framesizes = vicodec_enum_framesizes,
900
901         .vidioc_subscribe_event = vicodec_subscribe_event,
902         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
903 };
904
905
906 /*
907  * Queue operations
908  */
909
910 static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
911                                unsigned int *nplanes, unsigned int sizes[],
912                                struct device *alloc_devs[])
913 {
914         struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
915         struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
916         unsigned int size = q_data->sizeimage;
917
918         if (*nplanes)
919                 return sizes[0] < size ? -EINVAL : 0;
920
921         *nplanes = 1;
922         sizes[0] = size;
923         return 0;
924 }
925
926 static int vicodec_buf_prepare(struct vb2_buffer *vb)
927 {
928         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
929         struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
930         struct vicodec_q_data *q_data;
931
932         dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
933
934         q_data = get_q_data(ctx, vb->vb2_queue->type);
935         if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
936                 if (vbuf->field == V4L2_FIELD_ANY)
937                         vbuf->field = V4L2_FIELD_NONE;
938                 if (vbuf->field != V4L2_FIELD_NONE) {
939                         dprintk(ctx->dev, "%s field isn't supported\n",
940                                         __func__);
941                         return -EINVAL;
942                 }
943         }
944
945         if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
946                 dprintk(ctx->dev,
947                         "%s data will not fit into plane (%lu < %lu)\n",
948                         __func__, vb2_plane_size(vb, 0),
949                         (long)q_data->sizeimage);
950                 return -EINVAL;
951         }
952
953         return 0;
954 }
955
956 static void vicodec_buf_queue(struct vb2_buffer *vb)
957 {
958         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
959         struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
960
961         v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
962 }
963
964 static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
965 {
966         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
967         struct vb2_v4l2_buffer *vbuf;
968
969         for (;;) {
970                 if (V4L2_TYPE_IS_OUTPUT(q->type))
971                         vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
972                 else
973                         vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
974                 if (vbuf == NULL)
975                         return;
976                 spin_lock(ctx->lock);
977                 v4l2_m2m_buf_done(vbuf, state);
978                 spin_unlock(ctx->lock);
979         }
980 }
981
982 static int vicodec_start_streaming(struct vb2_queue *q,
983                                    unsigned int count)
984 {
985         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
986         struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
987         struct v4l2_fwht_state *state = &ctx->state;
988         unsigned int size = q_data->width * q_data->height;
989         const struct v4l2_fwht_pixfmt_info *info = q_data->info;
990         unsigned int chroma_div = info->width_div * info->height_div;
991         unsigned int total_planes_size;
992
993         /*
994          * we don't know ahead how many components are in the encoding type
995          * V4L2_PIX_FMT_FWHT, so we will allocate space for 4 planes.
996          */
997         if (info->id == V4L2_PIX_FMT_FWHT || info->components_num == 4)
998                 total_planes_size = 2 * size + 2 * (size / chroma_div);
999         else if (info->components_num == 3)
1000                 total_planes_size = size + 2 * (size / chroma_div);
1001         else
1002                 total_planes_size = size;
1003
1004         q_data->sequence = 0;
1005
1006         if (!V4L2_TYPE_IS_OUTPUT(q->type))
1007                 return 0;
1008
1009         state->width = q_data->width;
1010         state->height = q_data->height;
1011         state->ref_frame.width = state->ref_frame.height = 0;
1012         state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL);
1013         ctx->comp_max_size = total_planes_size + sizeof(struct fwht_cframe_hdr);
1014         state->compressed_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
1015         if (!state->ref_frame.luma || !state->compressed_frame) {
1016                 kvfree(state->ref_frame.luma);
1017                 kvfree(state->compressed_frame);
1018                 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1019                 return -ENOMEM;
1020         }
1021         if (info->id == V4L2_PIX_FMT_FWHT || info->components_num >= 3) {
1022                 state->ref_frame.cb = state->ref_frame.luma + size;
1023                 state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
1024         } else {
1025                 state->ref_frame.cb = NULL;
1026                 state->ref_frame.cr = NULL;
1027         }
1028
1029         if (info->id == V4L2_PIX_FMT_FWHT || info->components_num == 4)
1030                 state->ref_frame.alpha =
1031                         state->ref_frame.cr + size / chroma_div;
1032         else
1033                 state->ref_frame.alpha = NULL;
1034
1035         ctx->last_src_buf = NULL;
1036         ctx->last_dst_buf = NULL;
1037         state->gop_cnt = 0;
1038         ctx->cur_buf_offset = 0;
1039         ctx->comp_size = 0;
1040         ctx->comp_magic_cnt = 0;
1041         ctx->comp_has_frame = false;
1042
1043         return 0;
1044 }
1045
1046 static void vicodec_stop_streaming(struct vb2_queue *q)
1047 {
1048         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1049
1050         vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1051
1052         if (!V4L2_TYPE_IS_OUTPUT(q->type))
1053                 return;
1054
1055         kvfree(ctx->state.ref_frame.luma);
1056         kvfree(ctx->state.compressed_frame);
1057 }
1058
1059 static const struct vb2_ops vicodec_qops = {
1060         .queue_setup     = vicodec_queue_setup,
1061         .buf_prepare     = vicodec_buf_prepare,
1062         .buf_queue       = vicodec_buf_queue,
1063         .start_streaming = vicodec_start_streaming,
1064         .stop_streaming  = vicodec_stop_streaming,
1065         .wait_prepare    = vb2_ops_wait_prepare,
1066         .wait_finish     = vb2_ops_wait_finish,
1067 };
1068
1069 static int queue_init(void *priv, struct vb2_queue *src_vq,
1070                       struct vb2_queue *dst_vq)
1071 {
1072         struct vicodec_ctx *ctx = priv;
1073         int ret;
1074
1075         src_vq->type = (multiplanar ?
1076                         V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1077                         V4L2_BUF_TYPE_VIDEO_OUTPUT);
1078         src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1079         src_vq->drv_priv = ctx;
1080         src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1081         src_vq->ops = &vicodec_qops;
1082         src_vq->mem_ops = &vb2_vmalloc_memops;
1083         src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1084         src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex :
1085                 &ctx->dev->dec_mutex;
1086
1087         ret = vb2_queue_init(src_vq);
1088         if (ret)
1089                 return ret;
1090
1091         dst_vq->type = (multiplanar ?
1092                         V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1093                         V4L2_BUF_TYPE_VIDEO_CAPTURE);
1094         dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1095         dst_vq->drv_priv = ctx;
1096         dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1097         dst_vq->ops = &vicodec_qops;
1098         dst_vq->mem_ops = &vb2_vmalloc_memops;
1099         dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1100         dst_vq->lock = src_vq->lock;
1101
1102         return vb2_queue_init(dst_vq);
1103 }
1104
1105 #define VICODEC_CID_CUSTOM_BASE         (V4L2_CID_MPEG_BASE | 0xf000)
1106 #define VICODEC_CID_I_FRAME_QP          (VICODEC_CID_CUSTOM_BASE + 0)
1107 #define VICODEC_CID_P_FRAME_QP          (VICODEC_CID_CUSTOM_BASE + 1)
1108
1109 static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
1110 {
1111         struct vicodec_ctx *ctx = container_of(ctrl->handler,
1112                                                struct vicodec_ctx, hdl);
1113
1114         switch (ctrl->id) {
1115         case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1116                 ctx->state.gop_size = ctrl->val;
1117                 return 0;
1118         case VICODEC_CID_I_FRAME_QP:
1119                 ctx->state.i_frame_qp = ctrl->val;
1120                 return 0;
1121         case VICODEC_CID_P_FRAME_QP:
1122                 ctx->state.p_frame_qp = ctrl->val;
1123                 return 0;
1124         }
1125         return -EINVAL;
1126 }
1127
1128 static struct v4l2_ctrl_ops vicodec_ctrl_ops = {
1129         .s_ctrl = vicodec_s_ctrl,
1130 };
1131
1132 static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
1133         .ops = &vicodec_ctrl_ops,
1134         .id = VICODEC_CID_I_FRAME_QP,
1135         .name = "FWHT I-Frame QP Value",
1136         .type = V4L2_CTRL_TYPE_INTEGER,
1137         .min = 1,
1138         .max = 31,
1139         .def = 20,
1140         .step = 1,
1141 };
1142
1143 static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
1144         .ops = &vicodec_ctrl_ops,
1145         .id = VICODEC_CID_P_FRAME_QP,
1146         .name = "FWHT P-Frame QP Value",
1147         .type = V4L2_CTRL_TYPE_INTEGER,
1148         .min = 1,
1149         .max = 31,
1150         .def = 20,
1151         .step = 1,
1152 };
1153
1154 /*
1155  * File operations
1156  */
1157 static int vicodec_open(struct file *file)
1158 {
1159         struct video_device *vfd = video_devdata(file);
1160         struct vicodec_dev *dev = video_drvdata(file);
1161         struct vicodec_ctx *ctx = NULL;
1162         struct v4l2_ctrl_handler *hdl;
1163         unsigned int size;
1164         int rc = 0;
1165
1166         if (mutex_lock_interruptible(vfd->lock))
1167                 return -ERESTARTSYS;
1168         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1169         if (!ctx) {
1170                 rc = -ENOMEM;
1171                 goto open_unlock;
1172         }
1173
1174         if (vfd == &dev->enc_vfd)
1175                 ctx->is_enc = true;
1176
1177         v4l2_fh_init(&ctx->fh, video_devdata(file));
1178         file->private_data = &ctx->fh;
1179         ctx->dev = dev;
1180         hdl = &ctx->hdl;
1181         v4l2_ctrl_handler_init(hdl, 4);
1182         v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1183                           1, 16, 1, 10);
1184         v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
1185         v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
1186         if (hdl->error) {
1187                 rc = hdl->error;
1188                 v4l2_ctrl_handler_free(hdl);
1189                 kfree(ctx);
1190                 goto open_unlock;
1191         }
1192         ctx->fh.ctrl_handler = hdl;
1193         v4l2_ctrl_handler_setup(hdl);
1194
1195         ctx->q_data[V4L2_M2M_SRC].info =
1196                 ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
1197         ctx->q_data[V4L2_M2M_SRC].width = 1280;
1198         ctx->q_data[V4L2_M2M_SRC].height = 720;
1199         size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
1200                 ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
1201         if (ctx->is_enc)
1202                 ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
1203         else
1204                 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1205                         size + sizeof(struct fwht_cframe_hdr);
1206         ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1207         ctx->q_data[V4L2_M2M_DST].info =
1208                 ctx->is_enc ? &pixfmt_fwht : v4l2_fwht_get_pixfmt(0);
1209         size = 1280 * 720 * ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
1210                 ctx->q_data[V4L2_M2M_DST].info->sizeimage_div;
1211         if (ctx->is_enc)
1212                 ctx->q_data[V4L2_M2M_DST].sizeimage =
1213                         size + sizeof(struct fwht_cframe_hdr);
1214         else
1215                 ctx->q_data[V4L2_M2M_DST].sizeimage = size;
1216         ctx->state.colorspace = V4L2_COLORSPACE_REC709;
1217
1218         if (ctx->is_enc) {
1219                 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
1220                                                     &queue_init);
1221                 ctx->lock = &dev->enc_lock;
1222         } else {
1223                 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
1224                                                     &queue_init);
1225                 ctx->lock = &dev->dec_lock;
1226         }
1227
1228         if (IS_ERR(ctx->fh.m2m_ctx)) {
1229                 rc = PTR_ERR(ctx->fh.m2m_ctx);
1230
1231                 v4l2_ctrl_handler_free(hdl);
1232                 v4l2_fh_exit(&ctx->fh);
1233                 kfree(ctx);
1234                 goto open_unlock;
1235         }
1236
1237         v4l2_fh_add(&ctx->fh);
1238
1239 open_unlock:
1240         mutex_unlock(vfd->lock);
1241         return rc;
1242 }
1243
1244 static int vicodec_release(struct file *file)
1245 {
1246         struct video_device *vfd = video_devdata(file);
1247         struct vicodec_ctx *ctx = file2ctx(file);
1248
1249         v4l2_fh_del(&ctx->fh);
1250         v4l2_fh_exit(&ctx->fh);
1251         v4l2_ctrl_handler_free(&ctx->hdl);
1252         mutex_lock(vfd->lock);
1253         v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1254         mutex_unlock(vfd->lock);
1255         kfree(ctx);
1256
1257         return 0;
1258 }
1259
1260 static const struct v4l2_file_operations vicodec_fops = {
1261         .owner          = THIS_MODULE,
1262         .open           = vicodec_open,
1263         .release        = vicodec_release,
1264         .poll           = v4l2_m2m_fop_poll,
1265         .unlocked_ioctl = video_ioctl2,
1266         .mmap           = v4l2_m2m_fop_mmap,
1267 };
1268
1269 static const struct video_device vicodec_videodev = {
1270         .name           = VICODEC_NAME,
1271         .vfl_dir        = VFL_DIR_M2M,
1272         .fops           = &vicodec_fops,
1273         .ioctl_ops      = &vicodec_ioctl_ops,
1274         .minor          = -1,
1275         .release        = video_device_release_empty,
1276 };
1277
1278 static const struct v4l2_m2m_ops m2m_ops = {
1279         .device_run     = device_run,
1280         .job_ready      = job_ready,
1281 };
1282
1283 static int vicodec_probe(struct platform_device *pdev)
1284 {
1285         struct vicodec_dev *dev;
1286         struct video_device *vfd;
1287         int ret;
1288
1289         dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1290         if (!dev)
1291                 return -ENOMEM;
1292
1293         spin_lock_init(&dev->enc_lock);
1294         spin_lock_init(&dev->dec_lock);
1295
1296         ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1297         if (ret)
1298                 return ret;
1299
1300 #ifdef CONFIG_MEDIA_CONTROLLER
1301         dev->mdev.dev = &pdev->dev;
1302         strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
1303         media_device_init(&dev->mdev);
1304         dev->v4l2_dev.mdev = &dev->mdev;
1305 #endif
1306
1307         mutex_init(&dev->enc_mutex);
1308         mutex_init(&dev->dec_mutex);
1309
1310         platform_set_drvdata(pdev, dev);
1311
1312         dev->enc_dev = v4l2_m2m_init(&m2m_ops);
1313         if (IS_ERR(dev->enc_dev)) {
1314                 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1315                 ret = PTR_ERR(dev->enc_dev);
1316                 goto unreg_dev;
1317         }
1318
1319         dev->dec_dev = v4l2_m2m_init(&m2m_ops);
1320         if (IS_ERR(dev->dec_dev)) {
1321                 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1322                 ret = PTR_ERR(dev->dec_dev);
1323                 goto err_enc_m2m;
1324         }
1325
1326         dev->enc_vfd = vicodec_videodev;
1327         vfd = &dev->enc_vfd;
1328         vfd->lock = &dev->enc_mutex;
1329         vfd->v4l2_dev = &dev->v4l2_dev;
1330         strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
1331         vfd->device_caps = V4L2_CAP_STREAMING |
1332                 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1333         v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
1334         v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
1335         video_set_drvdata(vfd, dev);
1336
1337         ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1338         if (ret) {
1339                 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1340                 goto err_dec_m2m;
1341         }
1342         v4l2_info(&dev->v4l2_dev,
1343                         "Device registered as /dev/video%d\n", vfd->num);
1344
1345         dev->dec_vfd = vicodec_videodev;
1346         vfd = &dev->dec_vfd;
1347         vfd->lock = &dev->dec_mutex;
1348         vfd->v4l2_dev = &dev->v4l2_dev;
1349         vfd->device_caps = V4L2_CAP_STREAMING |
1350                 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1351         strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
1352         v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
1353         v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
1354         video_set_drvdata(vfd, dev);
1355
1356         ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1357         if (ret) {
1358                 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1359                 goto unreg_enc;
1360         }
1361         v4l2_info(&dev->v4l2_dev,
1362                         "Device registered as /dev/video%d\n", vfd->num);
1363
1364 #ifdef CONFIG_MEDIA_CONTROLLER
1365         ret = v4l2_m2m_register_media_controller(dev->enc_dev,
1366                         &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
1367         if (ret) {
1368                 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1369                 goto unreg_m2m;
1370         }
1371
1372         ret = v4l2_m2m_register_media_controller(dev->dec_dev,
1373                         &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER);
1374         if (ret) {
1375                 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1376                 goto unreg_m2m_enc_mc;
1377         }
1378
1379         ret = media_device_register(&dev->mdev);
1380         if (ret) {
1381                 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1382                 goto unreg_m2m_dec_mc;
1383         }
1384 #endif
1385         return 0;
1386
1387 #ifdef CONFIG_MEDIA_CONTROLLER
1388 unreg_m2m_dec_mc:
1389         v4l2_m2m_unregister_media_controller(dev->dec_dev);
1390 unreg_m2m_enc_mc:
1391         v4l2_m2m_unregister_media_controller(dev->enc_dev);
1392 unreg_m2m:
1393         video_unregister_device(&dev->dec_vfd);
1394 #endif
1395 unreg_enc:
1396         video_unregister_device(&dev->enc_vfd);
1397 err_dec_m2m:
1398         v4l2_m2m_release(dev->dec_dev);
1399 err_enc_m2m:
1400         v4l2_m2m_release(dev->enc_dev);
1401 unreg_dev:
1402         v4l2_device_unregister(&dev->v4l2_dev);
1403
1404         return ret;
1405 }
1406
1407 static int vicodec_remove(struct platform_device *pdev)
1408 {
1409         struct vicodec_dev *dev = platform_get_drvdata(pdev);
1410
1411         v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
1412
1413 #ifdef CONFIG_MEDIA_CONTROLLER
1414         media_device_unregister(&dev->mdev);
1415         v4l2_m2m_unregister_media_controller(dev->enc_dev);
1416         v4l2_m2m_unregister_media_controller(dev->dec_dev);
1417         media_device_cleanup(&dev->mdev);
1418 #endif
1419
1420         v4l2_m2m_release(dev->enc_dev);
1421         v4l2_m2m_release(dev->dec_dev);
1422         video_unregister_device(&dev->enc_vfd);
1423         video_unregister_device(&dev->dec_vfd);
1424         v4l2_device_unregister(&dev->v4l2_dev);
1425
1426         return 0;
1427 }
1428
1429 static struct platform_driver vicodec_pdrv = {
1430         .probe          = vicodec_probe,
1431         .remove         = vicodec_remove,
1432         .driver         = {
1433                 .name   = VICODEC_NAME,
1434         },
1435 };
1436
1437 static void __exit vicodec_exit(void)
1438 {
1439         platform_driver_unregister(&vicodec_pdrv);
1440         platform_device_unregister(&vicodec_pdev);
1441 }
1442
1443 static int __init vicodec_init(void)
1444 {
1445         int ret;
1446
1447         ret = platform_device_register(&vicodec_pdev);
1448         if (ret)
1449                 return ret;
1450
1451         ret = platform_driver_register(&vicodec_pdrv);
1452         if (ret)
1453                 platform_device_unregister(&vicodec_pdev);
1454
1455         return ret;
1456 }
1457
1458 module_init(vicodec_init);
1459 module_exit(vicodec_exit);