media: vicodec: change variable name for the return value of v4l2_fwht_encode
[linux-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, 1
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            coded_width;
79         unsigned int            coded_height;
80         unsigned int            visible_width;
81         unsigned int            visible_height;
82         unsigned int            sizeimage;
83         unsigned int            sequence;
84         const struct v4l2_fwht_pixfmt_info *info;
85 };
86
87 enum {
88         V4L2_M2M_SRC = 0,
89         V4L2_M2M_DST = 1,
90 };
91
92 struct vicodec_dev {
93         struct v4l2_device      v4l2_dev;
94         struct video_device     enc_vfd;
95         struct video_device     dec_vfd;
96 #ifdef CONFIG_MEDIA_CONTROLLER
97         struct media_device     mdev;
98 #endif
99
100         struct mutex            enc_mutex;
101         struct mutex            dec_mutex;
102         spinlock_t              enc_lock;
103         spinlock_t              dec_lock;
104
105         struct v4l2_m2m_dev     *enc_dev;
106         struct v4l2_m2m_dev     *dec_dev;
107 };
108
109 struct vicodec_ctx {
110         struct v4l2_fh          fh;
111         struct vicodec_dev      *dev;
112         bool                    is_enc;
113         spinlock_t              *lock;
114
115         struct v4l2_ctrl_handler hdl;
116
117         struct vb2_v4l2_buffer *last_src_buf;
118         struct vb2_v4l2_buffer *last_dst_buf;
119
120         /* Source and destination queue data */
121         struct vicodec_q_data   q_data[2];
122         struct v4l2_fwht_state  state;
123
124         u32                     cur_buf_offset;
125         u32                     comp_max_size;
126         u32                     comp_size;
127         u32                     header_size;
128         u32                     comp_magic_cnt;
129         bool                    comp_has_frame;
130         bool                    comp_has_next_frame;
131         bool                    first_source_change_sent;
132         bool                    source_changed;
133 };
134
135 static inline struct vicodec_ctx *file2ctx(struct file *file)
136 {
137         return container_of(file->private_data, struct vicodec_ctx, fh);
138 }
139
140 static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
141                                          enum v4l2_buf_type type)
142 {
143         switch (type) {
144         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
145         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
146                 return &ctx->q_data[V4L2_M2M_SRC];
147         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
148         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
149                 return &ctx->q_data[V4L2_M2M_DST];
150         default:
151                 break;
152         }
153         return NULL;
154 }
155
156 static int device_process(struct vicodec_ctx *ctx,
157                           struct vb2_v4l2_buffer *src_vb,
158                           struct vb2_v4l2_buffer *dst_vb)
159 {
160         struct vicodec_dev *dev = ctx->dev;
161         struct vicodec_q_data *q_dst;
162         struct v4l2_fwht_state *state = &ctx->state;
163         u8 *p_src, *p_dst;
164         int ret;
165
166         q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
167         if (ctx->is_enc)
168                 p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
169         else
170                 p_src = state->compressed_frame;
171         p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
172         if (!p_src || !p_dst) {
173                 v4l2_err(&dev->v4l2_dev,
174                          "Acquiring kernel pointers to buffers failed\n");
175                 return -EFAULT;
176         }
177
178         if (ctx->is_enc) {
179                 struct vicodec_q_data *q_src;
180                 int comp_sz_or_errcode;
181
182                 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
183                 state->info = q_src->info;
184                 comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst);
185                 if (comp_sz_or_errcode < 0)
186                         return comp_sz_or_errcode;
187                 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode);
188         } else {
189                 unsigned int comp_frame_size = ntohl(ctx->state.header.size);
190
191                 if (comp_frame_size > ctx->comp_max_size)
192                         return -EINVAL;
193                 state->info = q_dst->info;
194                 ret = v4l2_fwht_decode(state, p_src, p_dst);
195                 if (ret < 0)
196                         return ret;
197                 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage);
198         }
199
200         dst_vb->sequence = q_dst->sequence++;
201         dst_vb->flags &= ~V4L2_BUF_FLAG_LAST;
202         v4l2_m2m_buf_copy_metadata(src_vb, dst_vb, !ctx->is_enc);
203
204         return 0;
205 }
206
207 /*
208  * mem2mem callbacks
209  */
210 static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx,
211                                              u8 **pp, u32 sz)
212 {
213         static const u8 magic[] = {
214                 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
215         };
216         u8 *p = *pp;
217         u32 state;
218         u8 *header = (u8 *)&ctx->state.header;
219
220         state = VB2_BUF_STATE_DONE;
221
222         if (!ctx->header_size) {
223                 state = VB2_BUF_STATE_ERROR;
224                 for (; p < *pp + sz; p++) {
225                         u32 copy;
226
227                         p = memchr(p, magic[ctx->comp_magic_cnt],
228                                    *pp + sz - p);
229                         if (!p) {
230                                 ctx->comp_magic_cnt = 0;
231                                 p = *pp + sz;
232                                 break;
233                         }
234                         copy = sizeof(magic) - ctx->comp_magic_cnt;
235                         if (*pp + sz - p < copy)
236                                 copy = *pp + sz - p;
237
238                         memcpy(header + ctx->comp_magic_cnt, p, copy);
239                         ctx->comp_magic_cnt += copy;
240                         if (!memcmp(header, magic, ctx->comp_magic_cnt)) {
241                                 p += copy;
242                                 state = VB2_BUF_STATE_DONE;
243                                 break;
244                         }
245                         ctx->comp_magic_cnt = 0;
246                 }
247                 if (ctx->comp_magic_cnt < sizeof(magic)) {
248                         *pp = p;
249                         return state;
250                 }
251                 ctx->header_size = sizeof(magic);
252         }
253
254         if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
255                 u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size;
256
257                 if (*pp + sz - p < copy)
258                         copy = *pp + sz - p;
259
260                 memcpy(header + ctx->header_size, p, copy);
261                 p += copy;
262                 ctx->header_size += copy;
263         }
264         *pp = p;
265         return state;
266 }
267
268 /* device_run() - prepares and starts the device */
269 static void device_run(void *priv)
270 {
271         static const struct v4l2_event eos_event = {
272                 .type = V4L2_EVENT_EOS
273         };
274         struct vicodec_ctx *ctx = priv;
275         struct vicodec_dev *dev = ctx->dev;
276         struct vb2_v4l2_buffer *src_buf, *dst_buf;
277         struct vicodec_q_data *q_src;
278         u32 state;
279
280         src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
281         dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
282         q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
283
284         state = VB2_BUF_STATE_DONE;
285         if (device_process(ctx, src_buf, dst_buf))
286                 state = VB2_BUF_STATE_ERROR;
287         ctx->last_dst_buf = dst_buf;
288
289         spin_lock(ctx->lock);
290         if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
291                 dst_buf->flags |= V4L2_BUF_FLAG_LAST;
292                 v4l2_event_queue_fh(&ctx->fh, &eos_event);
293         }
294         if (ctx->is_enc) {
295                 src_buf->sequence = q_src->sequence++;
296                 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
297                 v4l2_m2m_buf_done(src_buf, state);
298         } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) {
299                 src_buf->sequence = q_src->sequence++;
300                 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
301                 v4l2_m2m_buf_done(src_buf, state);
302                 ctx->cur_buf_offset = 0;
303                 ctx->comp_has_next_frame = false;
304         }
305         v4l2_m2m_buf_done(dst_buf, state);
306         ctx->comp_size = 0;
307         ctx->header_size = 0;
308         ctx->comp_magic_cnt = 0;
309         ctx->comp_has_frame = false;
310         spin_unlock(ctx->lock);
311
312         if (ctx->is_enc)
313                 v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
314         else
315                 v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
316 }
317
318 static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state)
319 {
320         struct vb2_v4l2_buffer *src_buf;
321         struct vicodec_q_data *q_src;
322
323         q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
324         spin_lock(ctx->lock);
325         src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
326         src_buf->sequence = q_src->sequence++;
327         v4l2_m2m_buf_done(src_buf, state);
328         ctx->cur_buf_offset = 0;
329         spin_unlock(ctx->lock);
330 }
331
332 static const struct v4l2_fwht_pixfmt_info *
333 info_from_header(const struct fwht_cframe_hdr *p_hdr)
334 {
335         unsigned int flags = ntohl(p_hdr->flags);
336         unsigned int width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
337         unsigned int height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
338         unsigned int components_num = 3;
339         unsigned int pixenc = 0;
340         unsigned int version = ntohl(p_hdr->version);
341
342         if (version >= 2) {
343                 components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
344                                 FWHT_FL_COMPONENTS_NUM_OFFSET);
345                 pixenc = (flags & FWHT_FL_PIXENC_MSK);
346         }
347         return v4l2_fwht_default_fmt(width_div, height_div,
348                                      components_num, pixenc, 0);
349 }
350
351 static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr)
352 {
353         const struct v4l2_fwht_pixfmt_info *info;
354         unsigned int w = ntohl(p_hdr->width);
355         unsigned int h = ntohl(p_hdr->height);
356         unsigned int version = ntohl(p_hdr->version);
357         unsigned int flags = ntohl(p_hdr->flags);
358
359         if (!version || version > FWHT_VERSION)
360                 return false;
361
362         if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT)
363                 return false;
364
365         if (version >= 2) {
366                 unsigned int components_num = 1 +
367                         ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
368                         FWHT_FL_COMPONENTS_NUM_OFFSET);
369                 unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK;
370
371                 if (components_num == 0 || components_num > 4 || !pixenc)
372                         return false;
373         }
374
375         info = info_from_header(p_hdr);
376         if (!info)
377                 return false;
378         return true;
379 }
380
381 static void update_capture_data_from_header(struct vicodec_ctx *ctx)
382 {
383         struct vicodec_q_data *q_dst = get_q_data(ctx,
384                                                   V4L2_BUF_TYPE_VIDEO_CAPTURE);
385         const struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
386         const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr);
387         unsigned int flags = ntohl(p_hdr->flags);
388         unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
389         unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
390
391         q_dst->info = info;
392         q_dst->visible_width = ntohl(p_hdr->width);
393         q_dst->visible_height = ntohl(p_hdr->height);
394         q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div);
395         q_dst->coded_height = vic_round_dim(q_dst->visible_height,
396                                             hdr_height_div);
397
398         q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height *
399                 q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div;
400         ctx->state.colorspace = ntohl(p_hdr->colorspace);
401
402         ctx->state.xfer_func = ntohl(p_hdr->xfer_func);
403         ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
404         ctx->state.quantization = ntohl(p_hdr->quantization);
405 }
406
407 static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf,
408                             const struct vb2_v4l2_buffer *src_buf,
409                             struct vicodec_ctx *ctx)
410 {
411         struct vicodec_q_data *q_dst = get_q_data(ctx,
412                                                   V4L2_BUF_TYPE_VIDEO_CAPTURE);
413
414         vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
415         dst_buf->sequence = q_dst->sequence++;
416
417         v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc);
418         dst_buf->flags |= V4L2_BUF_FLAG_LAST;
419         v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
420 }
421
422 static int job_ready(void *priv)
423 {
424         static const u8 magic[] = {
425                 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff
426         };
427         struct vicodec_ctx *ctx = priv;
428         struct vb2_v4l2_buffer *src_buf;
429         u8 *p_src;
430         u8 *p;
431         u32 sz;
432         u32 state;
433         struct vicodec_q_data *q_dst = get_q_data(ctx,
434                                                   V4L2_BUF_TYPE_VIDEO_CAPTURE);
435         unsigned int flags;
436         unsigned int hdr_width_div;
437         unsigned int hdr_height_div;
438         unsigned int max_to_copy;
439         unsigned int comp_frame_size;
440
441         if (ctx->source_changed)
442                 return 0;
443         if (ctx->is_enc || ctx->comp_has_frame)
444                 return 1;
445
446 restart:
447         ctx->comp_has_next_frame = false;
448         src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
449         if (!src_buf)
450                 return 0;
451         p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
452         sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
453         p = p_src + ctx->cur_buf_offset;
454
455         state = VB2_BUF_STATE_DONE;
456
457         if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
458                 state = get_next_header(ctx, &p, p_src + sz - p);
459                 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
460                         job_remove_src_buf(ctx, state);
461                         goto restart;
462                 }
463         }
464
465         comp_frame_size = ntohl(ctx->state.header.size);
466
467         /*
468          * The current scanned frame might be the first frame of a new
469          * resolution so its size might be larger than ctx->comp_max_size.
470          * In that case it is copied up to the current buffer capacity and
471          * the copy will continue after allocating new large enough buffer
472          * when restreaming
473          */
474         max_to_copy = min(comp_frame_size, ctx->comp_max_size);
475
476         if (ctx->comp_size < max_to_copy) {
477                 u32 copy = max_to_copy - ctx->comp_size;
478
479                 if (copy > p_src + sz - p)
480                         copy = p_src + sz - p;
481
482                 memcpy(ctx->state.compressed_frame + ctx->comp_size,
483                        p, copy);
484                 p += copy;
485                 ctx->comp_size += copy;
486                 if (ctx->comp_size < max_to_copy) {
487                         job_remove_src_buf(ctx, state);
488                         goto restart;
489                 }
490         }
491         ctx->cur_buf_offset = p - p_src;
492         if (ctx->comp_size == comp_frame_size)
493                 ctx->comp_has_frame = true;
494         ctx->comp_has_next_frame = false;
495         if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >=
496                         sizeof(struct fwht_cframe_hdr)) {
497                 struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
498                 u32 frame_size = ntohl(p_hdr->size);
499                 u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
500
501                 if (!memcmp(p, magic, sizeof(magic)))
502                         ctx->comp_has_next_frame = remaining >= frame_size;
503         }
504         /*
505          * if the header is invalid the device_run will just drop the frame
506          * with an error
507          */
508         if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame)
509                 return 1;
510         flags = ntohl(ctx->state.header.flags);
511         hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
512         hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
513
514         if (ntohl(ctx->state.header.width) != q_dst->visible_width ||
515             ntohl(ctx->state.header.height) != q_dst->visible_height ||
516             !q_dst->info ||
517             hdr_width_div != q_dst->info->width_div ||
518             hdr_height_div != q_dst->info->height_div) {
519                 static const struct v4l2_event rs_event = {
520                         .type = V4L2_EVENT_SOURCE_CHANGE,
521                         .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
522                 };
523
524                 struct vb2_v4l2_buffer *dst_buf =
525                         v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
526
527                 update_capture_data_from_header(ctx);
528                 ctx->first_source_change_sent = true;
529                 v4l2_event_queue_fh(&ctx->fh, &rs_event);
530                 set_last_buffer(dst_buf, src_buf, ctx);
531                 ctx->source_changed = true;
532                 return 0;
533         }
534         return 1;
535 }
536
537 /*
538  * video ioctls
539  */
540
541 static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
542 {
543         const struct v4l2_fwht_pixfmt_info *info =
544                 v4l2_fwht_find_pixfmt(fmt);
545
546         if (!info)
547                 info = v4l2_fwht_get_pixfmt(0);
548         return info;
549 }
550
551 static int vidioc_querycap(struct file *file, void *priv,
552                            struct v4l2_capability *cap)
553 {
554         strncpy(cap->driver, VICODEC_NAME, sizeof(cap->driver) - 1);
555         strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1);
556         snprintf(cap->bus_info, sizeof(cap->bus_info),
557                         "platform:%s", VICODEC_NAME);
558         return 0;
559 }
560
561 static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
562                     bool is_out)
563 {
564         bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out);
565
566         if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
567                 return -EINVAL;
568         if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
569                 return -EINVAL;
570
571         if (is_uncomp) {
572                 const struct v4l2_fwht_pixfmt_info *info =
573                                         get_q_data(ctx, f->type)->info;
574
575                 if (!info || ctx->is_enc)
576                         info = v4l2_fwht_get_pixfmt(f->index);
577                 else
578                         info = v4l2_fwht_default_fmt(info->width_div,
579                                                      info->height_div,
580                                                      info->components_num,
581                                                      info->pixenc,
582                                                      f->index);
583                 if (!info)
584                         return -EINVAL;
585                 f->pixelformat = info->id;
586         } else {
587                 if (f->index)
588                         return -EINVAL;
589                 f->pixelformat = V4L2_PIX_FMT_FWHT;
590         }
591         return 0;
592 }
593
594 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
595                                    struct v4l2_fmtdesc *f)
596 {
597         struct vicodec_ctx *ctx = file2ctx(file);
598
599         return enum_fmt(f, ctx, false);
600 }
601
602 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
603                                    struct v4l2_fmtdesc *f)
604 {
605         struct vicodec_ctx *ctx = file2ctx(file);
606
607         return enum_fmt(f, ctx, true);
608 }
609
610 static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
611 {
612         struct vb2_queue *vq;
613         struct vicodec_q_data *q_data;
614         struct v4l2_pix_format_mplane *pix_mp;
615         struct v4l2_pix_format *pix;
616         const struct v4l2_fwht_pixfmt_info *info;
617
618         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
619         if (!vq)
620                 return -EINVAL;
621
622         q_data = get_q_data(ctx, f->type);
623         info = q_data->info;
624
625         if (!info)
626                 info = v4l2_fwht_get_pixfmt(0);
627
628         switch (f->type) {
629         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
630         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
631                 if (multiplanar)
632                         return -EINVAL;
633                 pix = &f->fmt.pix;
634                 pix->width = q_data->coded_width;
635                 pix->height = q_data->coded_height;
636                 pix->field = V4L2_FIELD_NONE;
637                 pix->pixelformat = info->id;
638                 pix->bytesperline = q_data->coded_width *
639                                         info->bytesperline_mult;
640                 pix->sizeimage = q_data->sizeimage;
641                 pix->colorspace = ctx->state.colorspace;
642                 pix->xfer_func = ctx->state.xfer_func;
643                 pix->ycbcr_enc = ctx->state.ycbcr_enc;
644                 pix->quantization = ctx->state.quantization;
645                 break;
646
647         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
648         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
649                 if (!multiplanar)
650                         return -EINVAL;
651                 pix_mp = &f->fmt.pix_mp;
652                 pix_mp->width = q_data->coded_width;
653                 pix_mp->height = q_data->coded_height;
654                 pix_mp->field = V4L2_FIELD_NONE;
655                 pix_mp->pixelformat = info->id;
656                 pix_mp->num_planes = 1;
657                 pix_mp->plane_fmt[0].bytesperline =
658                                 q_data->coded_width * info->bytesperline_mult;
659                 pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
660                 pix_mp->colorspace = ctx->state.colorspace;
661                 pix_mp->xfer_func = ctx->state.xfer_func;
662                 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
663                 pix_mp->quantization = ctx->state.quantization;
664                 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
665                 memset(pix_mp->plane_fmt[0].reserved, 0,
666                        sizeof(pix_mp->plane_fmt[0].reserved));
667                 break;
668         default:
669                 return -EINVAL;
670         }
671         return 0;
672 }
673
674 static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
675                                 struct v4l2_format *f)
676 {
677         return vidioc_g_fmt(file2ctx(file), f);
678 }
679
680 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
681                                 struct v4l2_format *f)
682 {
683         return vidioc_g_fmt(file2ctx(file), f);
684 }
685
686 static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
687 {
688         struct v4l2_pix_format_mplane *pix_mp;
689         struct v4l2_pix_format *pix;
690         struct v4l2_plane_pix_format *plane;
691         const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht;
692
693         switch (f->type) {
694         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
695         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
696                 pix = &f->fmt.pix;
697                 if (pix->pixelformat != V4L2_PIX_FMT_FWHT)
698                         info = find_fmt(pix->pixelformat);
699
700                 pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
701                 pix->width = vic_round_dim(pix->width, info->width_div);
702
703                 pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT);
704                 pix->height = vic_round_dim(pix->height, info->height_div);
705
706                 pix->field = V4L2_FIELD_NONE;
707                 pix->bytesperline =
708                         pix->width * info->bytesperline_mult;
709                 pix->sizeimage = pix->width * pix->height *
710                         info->sizeimage_mult / info->sizeimage_div;
711                 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
712                         pix->sizeimage += sizeof(struct fwht_cframe_hdr);
713                 break;
714         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
715         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
716                 pix_mp = &f->fmt.pix_mp;
717                 plane = pix_mp->plane_fmt;
718                 if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT)
719                         info = find_fmt(pix_mp->pixelformat);
720                 pix_mp->num_planes = 1;
721
722                 pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH);
723                 pix_mp->width = vic_round_dim(pix_mp->width, info->width_div);
724
725                 pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT);
726                 pix_mp->height = vic_round_dim(pix_mp->height,
727                                                info->height_div);
728
729                 pix_mp->field = V4L2_FIELD_NONE;
730                 plane->bytesperline =
731                         pix_mp->width * info->bytesperline_mult;
732                 plane->sizeimage = pix_mp->width * pix_mp->height *
733                         info->sizeimage_mult / info->sizeimage_div;
734                 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
735                         plane->sizeimage += sizeof(struct fwht_cframe_hdr);
736                 memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
737                 memset(plane->reserved, 0, sizeof(plane->reserved));
738                 break;
739         default:
740                 return -EINVAL;
741         }
742
743         return 0;
744 }
745
746 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
747                                   struct v4l2_format *f)
748 {
749         struct vicodec_ctx *ctx = file2ctx(file);
750         struct v4l2_pix_format_mplane *pix_mp;
751         struct v4l2_pix_format *pix;
752
753         switch (f->type) {
754         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
755                 if (multiplanar)
756                         return -EINVAL;
757                 pix = &f->fmt.pix;
758                 pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
759                                    find_fmt(f->fmt.pix.pixelformat)->id;
760                 pix->colorspace = ctx->state.colorspace;
761                 pix->xfer_func = ctx->state.xfer_func;
762                 pix->ycbcr_enc = ctx->state.ycbcr_enc;
763                 pix->quantization = ctx->state.quantization;
764                 break;
765         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
766                 if (!multiplanar)
767                         return -EINVAL;
768                 pix_mp = &f->fmt.pix_mp;
769                 pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
770                                       find_fmt(pix_mp->pixelformat)->id;
771                 pix_mp->colorspace = ctx->state.colorspace;
772                 pix_mp->xfer_func = ctx->state.xfer_func;
773                 pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
774                 pix_mp->quantization = ctx->state.quantization;
775                 break;
776         default:
777                 return -EINVAL;
778         }
779
780         return vidioc_try_fmt(ctx, f);
781 }
782
783 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
784                                   struct v4l2_format *f)
785 {
786         struct vicodec_ctx *ctx = file2ctx(file);
787         struct v4l2_pix_format_mplane *pix_mp;
788         struct v4l2_pix_format *pix;
789
790         switch (f->type) {
791         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
792                 if (multiplanar)
793                         return -EINVAL;
794                 pix = &f->fmt.pix;
795                 pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
796                                    find_fmt(pix->pixelformat)->id;
797                 if (!pix->colorspace)
798                         pix->colorspace = V4L2_COLORSPACE_REC709;
799                 break;
800         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
801                 if (!multiplanar)
802                         return -EINVAL;
803                 pix_mp = &f->fmt.pix_mp;
804                 pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
805                                       find_fmt(pix_mp->pixelformat)->id;
806                 if (!pix_mp->colorspace)
807                         pix_mp->colorspace = V4L2_COLORSPACE_REC709;
808                 break;
809         default:
810                 return -EINVAL;
811         }
812
813         return vidioc_try_fmt(ctx, f);
814 }
815
816 static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
817 {
818         struct vicodec_q_data *q_data;
819         struct vb2_queue *vq;
820         bool fmt_changed = true;
821         struct v4l2_pix_format_mplane *pix_mp;
822         struct v4l2_pix_format *pix;
823
824         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
825         if (!vq)
826                 return -EINVAL;
827
828         q_data = get_q_data(ctx, f->type);
829         if (!q_data)
830                 return -EINVAL;
831
832         switch (f->type) {
833         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
834         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
835                 pix = &f->fmt.pix;
836                 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
837                         fmt_changed =
838                                 !q_data->info ||
839                                 q_data->info->id != pix->pixelformat ||
840                                 q_data->coded_width != pix->width ||
841                                 q_data->coded_height != pix->height;
842
843                 if (vb2_is_busy(vq) && fmt_changed)
844                         return -EBUSY;
845
846                 if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
847                         q_data->info = &pixfmt_fwht;
848                 else
849                         q_data->info = find_fmt(pix->pixelformat);
850                 q_data->coded_width = pix->width;
851                 q_data->coded_height = pix->height;
852                 q_data->sizeimage = pix->sizeimage;
853                 break;
854         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
855         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
856                 pix_mp = &f->fmt.pix_mp;
857                 if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
858                         fmt_changed =
859                                 !q_data->info ||
860                                 q_data->info->id != pix_mp->pixelformat ||
861                                 q_data->coded_width != pix_mp->width ||
862                                 q_data->coded_height != pix_mp->height;
863
864                 if (vb2_is_busy(vq) && fmt_changed)
865                         return -EBUSY;
866
867                 if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
868                         q_data->info = &pixfmt_fwht;
869                 else
870                         q_data->info = find_fmt(pix_mp->pixelformat);
871                 q_data->coded_width = pix_mp->width;
872                 q_data->coded_height = pix_mp->height;
873                 q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
874                 break;
875         default:
876                 return -EINVAL;
877         }
878         if (q_data->visible_width > q_data->coded_width)
879                 q_data->visible_width = q_data->coded_width;
880         if (q_data->visible_height > q_data->coded_height)
881                 q_data->visible_height = q_data->coded_height;
882
883
884         dprintk(ctx->dev,
885                 "Setting format for type %d, coded wxh: %dx%d, visible wxh: %dx%d, fourcc: %08x\n",
886                 f->type, q_data->coded_width, q_data->coded_height,
887                 q_data->visible_width, q_data->visible_height,
888                 q_data->info->id);
889
890         return 0;
891 }
892
893 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
894                                 struct v4l2_format *f)
895 {
896         int ret;
897
898         ret = vidioc_try_fmt_vid_cap(file, priv, f);
899         if (ret)
900                 return ret;
901
902         return vidioc_s_fmt(file2ctx(file), f);
903 }
904
905 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
906                                 struct v4l2_format *f)
907 {
908         struct vicodec_ctx *ctx = file2ctx(file);
909         struct v4l2_pix_format_mplane *pix_mp;
910         struct v4l2_pix_format *pix;
911         int ret;
912
913         ret = vidioc_try_fmt_vid_out(file, priv, f);
914         if (ret)
915                 return ret;
916
917         ret = vidioc_s_fmt(file2ctx(file), f);
918         if (!ret) {
919                 switch (f->type) {
920                 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
921                 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
922                         pix = &f->fmt.pix;
923                         ctx->state.colorspace = pix->colorspace;
924                         ctx->state.xfer_func = pix->xfer_func;
925                         ctx->state.ycbcr_enc = pix->ycbcr_enc;
926                         ctx->state.quantization = pix->quantization;
927                         break;
928                 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
929                 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
930                         pix_mp = &f->fmt.pix_mp;
931                         ctx->state.colorspace = pix_mp->colorspace;
932                         ctx->state.xfer_func = pix_mp->xfer_func;
933                         ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
934                         ctx->state.quantization = pix_mp->quantization;
935                         break;
936                 default:
937                         break;
938                 }
939         }
940         return ret;
941 }
942
943 static int vidioc_g_selection(struct file *file, void *priv,
944                               struct v4l2_selection *s)
945 {
946         struct vicodec_ctx *ctx = file2ctx(file);
947         struct vicodec_q_data *q_data;
948
949         q_data = get_q_data(ctx, s->type);
950         if (!q_data)
951                 return -EINVAL;
952         /*
953          * encoder supports only cropping on the OUTPUT buffer
954          * decoder supports only composing on the CAPTURE buffer
955          */
956         if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
957                 switch (s->target) {
958                 case V4L2_SEL_TGT_CROP:
959                         s->r.left = 0;
960                         s->r.top = 0;
961                         s->r.width = q_data->visible_width;
962                         s->r.height = q_data->visible_height;
963                         return 0;
964                 case V4L2_SEL_TGT_CROP_DEFAULT:
965                 case V4L2_SEL_TGT_CROP_BOUNDS:
966                         s->r.left = 0;
967                         s->r.top = 0;
968                         s->r.width = q_data->coded_width;
969                         s->r.height = q_data->coded_height;
970                         return 0;
971                 }
972         } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
973                 switch (s->target) {
974                 case V4L2_SEL_TGT_COMPOSE:
975                         s->r.left = 0;
976                         s->r.top = 0;
977                         s->r.width = q_data->visible_width;
978                         s->r.height = q_data->visible_height;
979                         return 0;
980                 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
981                 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
982                         s->r.left = 0;
983                         s->r.top = 0;
984                         s->r.width = q_data->coded_width;
985                         s->r.height = q_data->coded_height;
986                         return 0;
987                 }
988         }
989         return -EINVAL;
990 }
991
992 static int vidioc_s_selection(struct file *file, void *priv,
993                               struct v4l2_selection *s)
994 {
995         struct vicodec_ctx *ctx = file2ctx(file);
996         struct vicodec_q_data *q_data;
997
998         if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
999                 return -EINVAL;
1000
1001         q_data = get_q_data(ctx, s->type);
1002         if (!q_data)
1003                 return -EINVAL;
1004
1005         if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP)
1006                 return -EINVAL;
1007
1008         s->r.left = 0;
1009         s->r.top = 0;
1010         q_data->visible_width = clamp(s->r.width, MIN_WIDTH,
1011                                       q_data->coded_width);
1012         s->r.width = q_data->visible_width;
1013         q_data->visible_height = clamp(s->r.height, MIN_HEIGHT,
1014                                        q_data->coded_height);
1015         s->r.height = q_data->visible_height;
1016         return 0;
1017 }
1018
1019 static void vicodec_mark_last_buf(struct vicodec_ctx *ctx)
1020 {
1021         static const struct v4l2_event eos_event = {
1022                 .type = V4L2_EVENT_EOS
1023         };
1024
1025         spin_lock(ctx->lock);
1026         ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
1027         if (!ctx->last_src_buf && ctx->last_dst_buf) {
1028                 ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
1029                 v4l2_event_queue_fh(&ctx->fh, &eos_event);
1030         }
1031         spin_unlock(ctx->lock);
1032 }
1033
1034 static int vicodec_try_encoder_cmd(struct file *file, void *fh,
1035                                 struct v4l2_encoder_cmd *ec)
1036 {
1037         if (ec->cmd != V4L2_ENC_CMD_STOP)
1038                 return -EINVAL;
1039
1040         if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
1041                 return -EINVAL;
1042
1043         return 0;
1044 }
1045
1046 static int vicodec_encoder_cmd(struct file *file, void *fh,
1047                             struct v4l2_encoder_cmd *ec)
1048 {
1049         struct vicodec_ctx *ctx = file2ctx(file);
1050         int ret;
1051
1052         ret = vicodec_try_encoder_cmd(file, fh, ec);
1053         if (ret < 0)
1054                 return ret;
1055
1056         vicodec_mark_last_buf(ctx);
1057         return 0;
1058 }
1059
1060 static int vicodec_try_decoder_cmd(struct file *file, void *fh,
1061                                 struct v4l2_decoder_cmd *dc)
1062 {
1063         if (dc->cmd != V4L2_DEC_CMD_STOP)
1064                 return -EINVAL;
1065
1066         if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
1067                 return -EINVAL;
1068
1069         if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
1070                 return -EINVAL;
1071
1072         return 0;
1073 }
1074
1075 static int vicodec_decoder_cmd(struct file *file, void *fh,
1076                             struct v4l2_decoder_cmd *dc)
1077 {
1078         struct vicodec_ctx *ctx = file2ctx(file);
1079         int ret;
1080
1081         ret = vicodec_try_decoder_cmd(file, fh, dc);
1082         if (ret < 0)
1083                 return ret;
1084
1085         vicodec_mark_last_buf(ctx);
1086         return 0;
1087 }
1088
1089 static int vicodec_enum_framesizes(struct file *file, void *fh,
1090                                    struct v4l2_frmsizeenum *fsize)
1091 {
1092         switch (fsize->pixel_format) {
1093         case V4L2_PIX_FMT_FWHT:
1094                 break;
1095         default:
1096                 if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
1097                         break;
1098                 return -EINVAL;
1099         }
1100
1101         if (fsize->index)
1102                 return -EINVAL;
1103
1104         fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
1105
1106         fsize->stepwise.min_width = MIN_WIDTH;
1107         fsize->stepwise.max_width = MAX_WIDTH;
1108         fsize->stepwise.step_width = 8;
1109         fsize->stepwise.min_height = MIN_HEIGHT;
1110         fsize->stepwise.max_height = MAX_HEIGHT;
1111         fsize->stepwise.step_height = 8;
1112
1113         return 0;
1114 }
1115
1116 static int vicodec_subscribe_event(struct v4l2_fh *fh,
1117                                 const struct v4l2_event_subscription *sub)
1118 {
1119         struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh);
1120
1121         switch (sub->type) {
1122         case V4L2_EVENT_SOURCE_CHANGE:
1123                 if (ctx->is_enc)
1124                         return -EINVAL;
1125                 /* fall through */
1126         case V4L2_EVENT_EOS:
1127                 return v4l2_event_subscribe(fh, sub, 0, NULL);
1128         default:
1129                 return v4l2_ctrl_subscribe_event(fh, sub);
1130         }
1131 }
1132
1133 static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
1134         .vidioc_querycap        = vidioc_querycap,
1135
1136         .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1137         .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
1138         .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1139         .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
1140
1141         .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
1142         .vidioc_g_fmt_vid_cap_mplane    = vidioc_g_fmt_vid_cap,
1143         .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap,
1144         .vidioc_s_fmt_vid_cap_mplane    = vidioc_s_fmt_vid_cap,
1145
1146         .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1147         .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
1148         .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1149         .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
1150
1151         .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
1152         .vidioc_g_fmt_vid_out_mplane    = vidioc_g_fmt_vid_out,
1153         .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out,
1154         .vidioc_s_fmt_vid_out_mplane    = vidioc_s_fmt_vid_out,
1155
1156         .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
1157         .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
1158         .vidioc_qbuf            = v4l2_m2m_ioctl_qbuf,
1159         .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
1160         .vidioc_prepare_buf     = v4l2_m2m_ioctl_prepare_buf,
1161         .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
1162         .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
1163
1164         .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
1165         .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
1166
1167         .vidioc_g_selection     = vidioc_g_selection,
1168         .vidioc_s_selection     = vidioc_s_selection,
1169
1170         .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd,
1171         .vidioc_encoder_cmd     = vicodec_encoder_cmd,
1172         .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd,
1173         .vidioc_decoder_cmd     = vicodec_decoder_cmd,
1174         .vidioc_enum_framesizes = vicodec_enum_framesizes,
1175
1176         .vidioc_subscribe_event = vicodec_subscribe_event,
1177         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1178 };
1179
1180
1181 /*
1182  * Queue operations
1183  */
1184
1185 static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1186                                unsigned int *nplanes, unsigned int sizes[],
1187                                struct device *alloc_devs[])
1188 {
1189         struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
1190         struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
1191         unsigned int size = q_data->sizeimage;
1192
1193         if (*nplanes)
1194                 return sizes[0] < size ? -EINVAL : 0;
1195
1196         *nplanes = 1;
1197         sizes[0] = size;
1198         return 0;
1199 }
1200
1201 static int vicodec_buf_prepare(struct vb2_buffer *vb)
1202 {
1203         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1204         struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1205         struct vicodec_q_data *q_data;
1206
1207         dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
1208
1209         q_data = get_q_data(ctx, vb->vb2_queue->type);
1210         if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1211                 if (vbuf->field == V4L2_FIELD_ANY)
1212                         vbuf->field = V4L2_FIELD_NONE;
1213                 if (vbuf->field != V4L2_FIELD_NONE) {
1214                         dprintk(ctx->dev, "%s field isn't supported\n",
1215                                         __func__);
1216                         return -EINVAL;
1217                 }
1218         }
1219
1220         if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
1221                 dprintk(ctx->dev,
1222                         "%s data will not fit into plane (%lu < %lu)\n",
1223                         __func__, vb2_plane_size(vb, 0),
1224                         (long)q_data->sizeimage);
1225                 return -EINVAL;
1226         }
1227
1228         return 0;
1229 }
1230
1231 static void vicodec_buf_queue(struct vb2_buffer *vb)
1232 {
1233         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1234         struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1235         unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
1236         u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
1237         u8 *p = p_src;
1238         struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1239                                                    V4L2_BUF_TYPE_VIDEO_OUTPUT);
1240         struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1241                                                    V4L2_BUF_TYPE_VIDEO_CAPTURE);
1242         bool header_valid = false;
1243         static const struct v4l2_event rs_event = {
1244                 .type = V4L2_EVENT_SOURCE_CHANGE,
1245                 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
1246         };
1247
1248         /* buf_queue handles only the first source change event */
1249         if (ctx->first_source_change_sent) {
1250                 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1251                 return;
1252         }
1253
1254         /*
1255          * if both queues are streaming, the source change event is
1256          * handled in job_ready
1257          */
1258         if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) {
1259                 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1260                 return;
1261         }
1262
1263         /*
1264          * source change event is relevant only for the decoder
1265          * in the compressed stream
1266          */
1267         if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1268                 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1269                 return;
1270         }
1271
1272         do {
1273                 enum vb2_buffer_state state =
1274                         get_next_header(ctx, &p, p_src + sz - p);
1275
1276                 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
1277                         v4l2_m2m_buf_done(vbuf, state);
1278                         return;
1279                 }
1280                 header_valid = is_header_valid(&ctx->state.header);
1281                 /*
1282                  * p points right after the end of the header in the
1283                  * buffer. If the header is invalid we set p to point
1284                  * to the next byte after the start of the header
1285                  */
1286                 if (!header_valid) {
1287                         p = p - sizeof(struct fwht_cframe_hdr) + 1;
1288                         if (p < p_src)
1289                                 p = p_src;
1290                         ctx->header_size = 0;
1291                         ctx->comp_magic_cnt = 0;
1292                 }
1293
1294         } while (!header_valid);
1295
1296         ctx->cur_buf_offset = p - p_src;
1297         update_capture_data_from_header(ctx);
1298         ctx->first_source_change_sent = true;
1299         v4l2_event_queue_fh(&ctx->fh, &rs_event);
1300         v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1301 }
1302
1303 static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
1304 {
1305         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1306         struct vb2_v4l2_buffer *vbuf;
1307
1308         for (;;) {
1309                 if (V4L2_TYPE_IS_OUTPUT(q->type))
1310                         vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1311                 else
1312                         vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1313                 if (vbuf == NULL)
1314                         return;
1315                 spin_lock(ctx->lock);
1316                 v4l2_m2m_buf_done(vbuf, state);
1317                 spin_unlock(ctx->lock);
1318         }
1319 }
1320
1321 static int vicodec_start_streaming(struct vb2_queue *q,
1322                                    unsigned int count)
1323 {
1324         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1325         struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
1326         struct v4l2_fwht_state *state = &ctx->state;
1327         const struct v4l2_fwht_pixfmt_info *info = q_data->info;
1328         unsigned int size = q_data->coded_width * q_data->coded_height;
1329         unsigned int chroma_div;
1330         unsigned int total_planes_size;
1331         u8 *new_comp_frame;
1332
1333         if (!info)
1334                 return -EINVAL;
1335
1336         chroma_div = info->width_div * info->height_div;
1337         q_data->sequence = 0;
1338
1339         if (V4L2_TYPE_IS_OUTPUT(q->type))
1340                 ctx->last_src_buf = NULL;
1341         else
1342                 ctx->last_dst_buf = NULL;
1343
1344         state->gop_cnt = 0;
1345
1346         if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1347             (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc))
1348                 return 0;
1349
1350         if (info->id == V4L2_PIX_FMT_FWHT) {
1351                 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1352                 return -EINVAL;
1353         }
1354         if (info->components_num == 4)
1355                 total_planes_size = 2 * size + 2 * (size / chroma_div);
1356         else if (info->components_num == 3)
1357                 total_planes_size = size + 2 * (size / chroma_div);
1358         else
1359                 total_planes_size = size;
1360
1361         state->visible_width = q_data->visible_width;
1362         state->visible_height = q_data->visible_height;
1363         state->coded_width = q_data->coded_width;
1364         state->coded_height = q_data->coded_height;
1365         state->stride = q_data->coded_width *
1366                                 info->bytesperline_mult;
1367
1368         state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL);
1369         ctx->comp_max_size = total_planes_size;
1370         new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
1371
1372         if (!state->ref_frame.luma || !new_comp_frame) {
1373                 kvfree(state->ref_frame.luma);
1374                 kvfree(new_comp_frame);
1375                 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1376                 return -ENOMEM;
1377         }
1378         /*
1379          * if state->compressed_frame was already allocated then
1380          * it contain data of the first frame of the new resolution
1381          */
1382         if (state->compressed_frame) {
1383                 if (ctx->comp_size > ctx->comp_max_size)
1384                         ctx->comp_size = ctx->comp_max_size;
1385
1386                 memcpy(new_comp_frame,
1387                        state->compressed_frame, ctx->comp_size);
1388         }
1389
1390         kvfree(state->compressed_frame);
1391         state->compressed_frame = new_comp_frame;
1392
1393         if (info->components_num >= 3) {
1394                 state->ref_frame.cb = state->ref_frame.luma + size;
1395                 state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
1396         } else {
1397                 state->ref_frame.cb = NULL;
1398                 state->ref_frame.cr = NULL;
1399         }
1400
1401         if (info->components_num == 4)
1402                 state->ref_frame.alpha =
1403                         state->ref_frame.cr + size / chroma_div;
1404         else
1405                 state->ref_frame.alpha = NULL;
1406         return 0;
1407 }
1408
1409 static void vicodec_stop_streaming(struct vb2_queue *q)
1410 {
1411         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1412
1413         vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1414
1415         if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1416             (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) {
1417                 kvfree(ctx->state.ref_frame.luma);
1418                 ctx->comp_max_size = 0;
1419                 ctx->source_changed = false;
1420         }
1421         if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) {
1422                 ctx->cur_buf_offset = 0;
1423                 ctx->comp_size = 0;
1424                 ctx->header_size = 0;
1425                 ctx->comp_magic_cnt = 0;
1426                 ctx->comp_has_frame = 0;
1427                 ctx->comp_has_next_frame = 0;
1428         }
1429 }
1430
1431 static const struct vb2_ops vicodec_qops = {
1432         .queue_setup     = vicodec_queue_setup,
1433         .buf_prepare     = vicodec_buf_prepare,
1434         .buf_queue       = vicodec_buf_queue,
1435         .start_streaming = vicodec_start_streaming,
1436         .stop_streaming  = vicodec_stop_streaming,
1437         .wait_prepare    = vb2_ops_wait_prepare,
1438         .wait_finish     = vb2_ops_wait_finish,
1439 };
1440
1441 static int queue_init(void *priv, struct vb2_queue *src_vq,
1442                       struct vb2_queue *dst_vq)
1443 {
1444         struct vicodec_ctx *ctx = priv;
1445         int ret;
1446
1447         src_vq->type = (multiplanar ?
1448                         V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1449                         V4L2_BUF_TYPE_VIDEO_OUTPUT);
1450         src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1451         src_vq->drv_priv = ctx;
1452         src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1453         src_vq->ops = &vicodec_qops;
1454         src_vq->mem_ops = &vb2_vmalloc_memops;
1455         src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1456         src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex :
1457                 &ctx->dev->dec_mutex;
1458
1459         ret = vb2_queue_init(src_vq);
1460         if (ret)
1461                 return ret;
1462
1463         dst_vq->type = (multiplanar ?
1464                         V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1465                         V4L2_BUF_TYPE_VIDEO_CAPTURE);
1466         dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1467         dst_vq->drv_priv = ctx;
1468         dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1469         dst_vq->ops = &vicodec_qops;
1470         dst_vq->mem_ops = &vb2_vmalloc_memops;
1471         dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1472         dst_vq->lock = src_vq->lock;
1473
1474         return vb2_queue_init(dst_vq);
1475 }
1476
1477 #define VICODEC_CID_CUSTOM_BASE         (V4L2_CID_MPEG_BASE | 0xf000)
1478 #define VICODEC_CID_I_FRAME_QP          (VICODEC_CID_CUSTOM_BASE + 0)
1479 #define VICODEC_CID_P_FRAME_QP          (VICODEC_CID_CUSTOM_BASE + 1)
1480
1481 static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
1482 {
1483         struct vicodec_ctx *ctx = container_of(ctrl->handler,
1484                                                struct vicodec_ctx, hdl);
1485
1486         switch (ctrl->id) {
1487         case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1488                 ctx->state.gop_size = ctrl->val;
1489                 return 0;
1490         case VICODEC_CID_I_FRAME_QP:
1491                 ctx->state.i_frame_qp = ctrl->val;
1492                 return 0;
1493         case VICODEC_CID_P_FRAME_QP:
1494                 ctx->state.p_frame_qp = ctrl->val;
1495                 return 0;
1496         }
1497         return -EINVAL;
1498 }
1499
1500 static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
1501         .s_ctrl = vicodec_s_ctrl,
1502 };
1503
1504 static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
1505         .ops = &vicodec_ctrl_ops,
1506         .id = VICODEC_CID_I_FRAME_QP,
1507         .name = "FWHT I-Frame QP Value",
1508         .type = V4L2_CTRL_TYPE_INTEGER,
1509         .min = 1,
1510         .max = 31,
1511         .def = 20,
1512         .step = 1,
1513 };
1514
1515 static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
1516         .ops = &vicodec_ctrl_ops,
1517         .id = VICODEC_CID_P_FRAME_QP,
1518         .name = "FWHT P-Frame QP Value",
1519         .type = V4L2_CTRL_TYPE_INTEGER,
1520         .min = 1,
1521         .max = 31,
1522         .def = 20,
1523         .step = 1,
1524 };
1525
1526 /*
1527  * File operations
1528  */
1529 static int vicodec_open(struct file *file)
1530 {
1531         struct video_device *vfd = video_devdata(file);
1532         struct vicodec_dev *dev = video_drvdata(file);
1533         struct vicodec_ctx *ctx = NULL;
1534         struct v4l2_ctrl_handler *hdl;
1535         unsigned int size;
1536         int rc = 0;
1537
1538         if (mutex_lock_interruptible(vfd->lock))
1539                 return -ERESTARTSYS;
1540         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1541         if (!ctx) {
1542                 rc = -ENOMEM;
1543                 goto open_unlock;
1544         }
1545
1546         if (vfd == &dev->enc_vfd)
1547                 ctx->is_enc = true;
1548
1549         v4l2_fh_init(&ctx->fh, video_devdata(file));
1550         file->private_data = &ctx->fh;
1551         ctx->dev = dev;
1552         hdl = &ctx->hdl;
1553         v4l2_ctrl_handler_init(hdl, 4);
1554         v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1555                           1, 16, 1, 10);
1556         v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
1557         v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
1558         if (hdl->error) {
1559                 rc = hdl->error;
1560                 v4l2_ctrl_handler_free(hdl);
1561                 kfree(ctx);
1562                 goto open_unlock;
1563         }
1564         ctx->fh.ctrl_handler = hdl;
1565         v4l2_ctrl_handler_setup(hdl);
1566
1567         ctx->q_data[V4L2_M2M_SRC].info =
1568                 ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
1569         ctx->q_data[V4L2_M2M_SRC].coded_width = 1280;
1570         ctx->q_data[V4L2_M2M_SRC].coded_height = 720;
1571         ctx->q_data[V4L2_M2M_SRC].visible_width = 1280;
1572         ctx->q_data[V4L2_M2M_SRC].visible_height = 720;
1573         size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
1574                 ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
1575         if (ctx->is_enc)
1576                 ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
1577         else
1578                 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1579                         size + sizeof(struct fwht_cframe_hdr);
1580         if (ctx->is_enc) {
1581                 ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1582                 ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht;
1583                 ctx->q_data[V4L2_M2M_DST].sizeimage = 1280 * 720 *
1584                         ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
1585                         ctx->q_data[V4L2_M2M_DST].info->sizeimage_div +
1586                         sizeof(struct fwht_cframe_hdr);
1587         } else {
1588                 ctx->q_data[V4L2_M2M_DST].info = NULL;
1589         }
1590
1591         ctx->state.colorspace = V4L2_COLORSPACE_REC709;
1592
1593         if (ctx->is_enc) {
1594                 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
1595                                                     &queue_init);
1596                 ctx->lock = &dev->enc_lock;
1597         } else {
1598                 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
1599                                                     &queue_init);
1600                 ctx->lock = &dev->dec_lock;
1601         }
1602
1603         if (IS_ERR(ctx->fh.m2m_ctx)) {
1604                 rc = PTR_ERR(ctx->fh.m2m_ctx);
1605
1606                 v4l2_ctrl_handler_free(hdl);
1607                 v4l2_fh_exit(&ctx->fh);
1608                 kfree(ctx);
1609                 goto open_unlock;
1610         }
1611
1612         v4l2_fh_add(&ctx->fh);
1613
1614 open_unlock:
1615         mutex_unlock(vfd->lock);
1616         return rc;
1617 }
1618
1619 static int vicodec_release(struct file *file)
1620 {
1621         struct video_device *vfd = video_devdata(file);
1622         struct vicodec_ctx *ctx = file2ctx(file);
1623
1624         mutex_lock(vfd->lock);
1625         v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1626         mutex_unlock(vfd->lock);
1627         v4l2_fh_del(&ctx->fh);
1628         v4l2_fh_exit(&ctx->fh);
1629         v4l2_ctrl_handler_free(&ctx->hdl);
1630         kfree(ctx);
1631
1632         return 0;
1633 }
1634
1635 static const struct v4l2_file_operations vicodec_fops = {
1636         .owner          = THIS_MODULE,
1637         .open           = vicodec_open,
1638         .release        = vicodec_release,
1639         .poll           = v4l2_m2m_fop_poll,
1640         .unlocked_ioctl = video_ioctl2,
1641         .mmap           = v4l2_m2m_fop_mmap,
1642 };
1643
1644 static const struct video_device vicodec_videodev = {
1645         .name           = VICODEC_NAME,
1646         .vfl_dir        = VFL_DIR_M2M,
1647         .fops           = &vicodec_fops,
1648         .ioctl_ops      = &vicodec_ioctl_ops,
1649         .minor          = -1,
1650         .release        = video_device_release_empty,
1651 };
1652
1653 static const struct v4l2_m2m_ops m2m_ops = {
1654         .device_run     = device_run,
1655         .job_ready      = job_ready,
1656 };
1657
1658 static int vicodec_probe(struct platform_device *pdev)
1659 {
1660         struct vicodec_dev *dev;
1661         struct video_device *vfd;
1662         int ret;
1663
1664         dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1665         if (!dev)
1666                 return -ENOMEM;
1667
1668         spin_lock_init(&dev->enc_lock);
1669         spin_lock_init(&dev->dec_lock);
1670
1671         ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1672         if (ret)
1673                 return ret;
1674
1675 #ifdef CONFIG_MEDIA_CONTROLLER
1676         dev->mdev.dev = &pdev->dev;
1677         strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
1678         strscpy(dev->mdev.bus_info, "platform:vicodec",
1679                 sizeof(dev->mdev.bus_info));
1680         media_device_init(&dev->mdev);
1681         dev->v4l2_dev.mdev = &dev->mdev;
1682 #endif
1683
1684         mutex_init(&dev->enc_mutex);
1685         mutex_init(&dev->dec_mutex);
1686
1687         platform_set_drvdata(pdev, dev);
1688
1689         dev->enc_dev = v4l2_m2m_init(&m2m_ops);
1690         if (IS_ERR(dev->enc_dev)) {
1691                 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1692                 ret = PTR_ERR(dev->enc_dev);
1693                 goto unreg_dev;
1694         }
1695
1696         dev->dec_dev = v4l2_m2m_init(&m2m_ops);
1697         if (IS_ERR(dev->dec_dev)) {
1698                 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1699                 ret = PTR_ERR(dev->dec_dev);
1700                 goto err_enc_m2m;
1701         }
1702
1703         dev->enc_vfd = vicodec_videodev;
1704         vfd = &dev->enc_vfd;
1705         vfd->lock = &dev->enc_mutex;
1706         vfd->v4l2_dev = &dev->v4l2_dev;
1707         strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
1708         vfd->device_caps = V4L2_CAP_STREAMING |
1709                 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1710         v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
1711         v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
1712         video_set_drvdata(vfd, dev);
1713
1714         ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1715         if (ret) {
1716                 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1717                 goto err_dec_m2m;
1718         }
1719         v4l2_info(&dev->v4l2_dev,
1720                         "Device registered as /dev/video%d\n", vfd->num);
1721
1722         dev->dec_vfd = vicodec_videodev;
1723         vfd = &dev->dec_vfd;
1724         vfd->lock = &dev->dec_mutex;
1725         vfd->v4l2_dev = &dev->v4l2_dev;
1726         vfd->device_caps = V4L2_CAP_STREAMING |
1727                 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1728         strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
1729         v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
1730         v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
1731         video_set_drvdata(vfd, dev);
1732
1733         ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1734         if (ret) {
1735                 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1736                 goto unreg_enc;
1737         }
1738         v4l2_info(&dev->v4l2_dev,
1739                         "Device registered as /dev/video%d\n", vfd->num);
1740
1741 #ifdef CONFIG_MEDIA_CONTROLLER
1742         ret = v4l2_m2m_register_media_controller(dev->enc_dev,
1743                         &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
1744         if (ret) {
1745                 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1746                 goto unreg_m2m;
1747         }
1748
1749         ret = v4l2_m2m_register_media_controller(dev->dec_dev,
1750                         &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER);
1751         if (ret) {
1752                 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1753                 goto unreg_m2m_enc_mc;
1754         }
1755
1756         ret = media_device_register(&dev->mdev);
1757         if (ret) {
1758                 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1759                 goto unreg_m2m_dec_mc;
1760         }
1761 #endif
1762         return 0;
1763
1764 #ifdef CONFIG_MEDIA_CONTROLLER
1765 unreg_m2m_dec_mc:
1766         v4l2_m2m_unregister_media_controller(dev->dec_dev);
1767 unreg_m2m_enc_mc:
1768         v4l2_m2m_unregister_media_controller(dev->enc_dev);
1769 unreg_m2m:
1770         video_unregister_device(&dev->dec_vfd);
1771 #endif
1772 unreg_enc:
1773         video_unregister_device(&dev->enc_vfd);
1774 err_dec_m2m:
1775         v4l2_m2m_release(dev->dec_dev);
1776 err_enc_m2m:
1777         v4l2_m2m_release(dev->enc_dev);
1778 unreg_dev:
1779         v4l2_device_unregister(&dev->v4l2_dev);
1780
1781         return ret;
1782 }
1783
1784 static int vicodec_remove(struct platform_device *pdev)
1785 {
1786         struct vicodec_dev *dev = platform_get_drvdata(pdev);
1787
1788         v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
1789
1790 #ifdef CONFIG_MEDIA_CONTROLLER
1791         media_device_unregister(&dev->mdev);
1792         v4l2_m2m_unregister_media_controller(dev->enc_dev);
1793         v4l2_m2m_unregister_media_controller(dev->dec_dev);
1794         media_device_cleanup(&dev->mdev);
1795 #endif
1796
1797         v4l2_m2m_release(dev->enc_dev);
1798         v4l2_m2m_release(dev->dec_dev);
1799         video_unregister_device(&dev->enc_vfd);
1800         video_unregister_device(&dev->dec_vfd);
1801         v4l2_device_unregister(&dev->v4l2_dev);
1802
1803         return 0;
1804 }
1805
1806 static struct platform_driver vicodec_pdrv = {
1807         .probe          = vicodec_probe,
1808         .remove         = vicodec_remove,
1809         .driver         = {
1810                 .name   = VICODEC_NAME,
1811         },
1812 };
1813
1814 static void __exit vicodec_exit(void)
1815 {
1816         platform_driver_unregister(&vicodec_pdrv);
1817         platform_device_unregister(&vicodec_pdev);
1818 }
1819
1820 static int __init vicodec_init(void)
1821 {
1822         int ret;
1823
1824         ret = platform_device_register(&vicodec_pdev);
1825         if (ret)
1826                 return ret;
1827
1828         ret = platform_driver_register(&vicodec_pdrv);
1829         if (ret)
1830                 platform_device_unregister(&vicodec_pdev);
1831
1832         return ret;
1833 }
1834
1835 module_init(vicodec_init);
1836 module_exit(vicodec_exit);