Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu
[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                 WARN_ON(1);
152                 break;
153         }
154         return NULL;
155 }
156
157 static int device_process(struct vicodec_ctx *ctx,
158                           struct vb2_v4l2_buffer *src_vb,
159                           struct vb2_v4l2_buffer *dst_vb)
160 {
161         struct vicodec_dev *dev = ctx->dev;
162         struct vicodec_q_data *q_dst;
163         struct v4l2_fwht_state *state = &ctx->state;
164         u8 *p_src, *p_dst;
165         int ret;
166
167         q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
168         if (ctx->is_enc)
169                 p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
170         else
171                 p_src = state->compressed_frame;
172         p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
173         if (!p_src || !p_dst) {
174                 v4l2_err(&dev->v4l2_dev,
175                          "Acquiring kernel pointers to buffers failed\n");
176                 return -EFAULT;
177         }
178
179         if (ctx->is_enc) {
180                 struct vicodec_q_data *q_src;
181
182                 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
183                 state->info = q_src->info;
184                 ret = v4l2_fwht_encode(state, p_src, p_dst);
185                 if (ret < 0)
186                         return ret;
187                 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret);
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         enum v4l2_buf_type valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
949         enum v4l2_buf_type valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
950
951         if (multiplanar) {
952                 valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
953                 valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
954         }
955
956         if (s->type != valid_cap_type && s->type != valid_out_type)
957                 return -EINVAL;
958
959         q_data = get_q_data(ctx, s->type);
960         if (!q_data)
961                 return -EINVAL;
962         /*
963          * encoder supports only cropping on the OUTPUT buffer
964          * decoder supports only composing on the CAPTURE buffer
965          */
966         if ((ctx->is_enc && s->type == valid_out_type) ||
967             (!ctx->is_enc && s->type == valid_cap_type)) {
968                 switch (s->target) {
969                 case V4L2_SEL_TGT_COMPOSE:
970                 case V4L2_SEL_TGT_CROP:
971                         s->r.left = 0;
972                         s->r.top = 0;
973                         s->r.width = q_data->visible_width;
974                         s->r.height = q_data->visible_height;
975                         return 0;
976                 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
977                 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
978                 case V4L2_SEL_TGT_CROP_DEFAULT:
979                 case V4L2_SEL_TGT_CROP_BOUNDS:
980                         s->r.left = 0;
981                         s->r.top = 0;
982                         s->r.width = q_data->coded_width;
983                         s->r.height = q_data->coded_height;
984                         return 0;
985                 }
986         }
987         return -EINVAL;
988 }
989
990 static int vidioc_s_selection(struct file *file, void *priv,
991                               struct v4l2_selection *s)
992 {
993         struct vicodec_ctx *ctx = file2ctx(file);
994         struct vicodec_q_data *q_data;
995         enum v4l2_buf_type out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
996
997         if (multiplanar)
998                 out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
999
1000         if (s->type != out_type)
1001                 return -EINVAL;
1002
1003         q_data = get_q_data(ctx, s->type);
1004         if (!q_data)
1005                 return -EINVAL;
1006
1007         if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP)
1008                 return -EINVAL;
1009
1010         s->r.left = 0;
1011         s->r.top = 0;
1012         q_data->visible_width = clamp(s->r.width, MIN_WIDTH,
1013                                       q_data->coded_width);
1014         s->r.width = q_data->visible_width;
1015         q_data->visible_height = clamp(s->r.height, MIN_HEIGHT,
1016                                        q_data->coded_height);
1017         s->r.height = q_data->visible_height;
1018         return 0;
1019 }
1020
1021 static void vicodec_mark_last_buf(struct vicodec_ctx *ctx)
1022 {
1023         static const struct v4l2_event eos_event = {
1024                 .type = V4L2_EVENT_EOS
1025         };
1026
1027         spin_lock(ctx->lock);
1028         ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
1029         if (!ctx->last_src_buf && ctx->last_dst_buf) {
1030                 ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
1031                 v4l2_event_queue_fh(&ctx->fh, &eos_event);
1032         }
1033         spin_unlock(ctx->lock);
1034 }
1035
1036 static int vicodec_try_encoder_cmd(struct file *file, void *fh,
1037                                 struct v4l2_encoder_cmd *ec)
1038 {
1039         if (ec->cmd != V4L2_ENC_CMD_STOP)
1040                 return -EINVAL;
1041
1042         if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END)
1043                 return -EINVAL;
1044
1045         return 0;
1046 }
1047
1048 static int vicodec_encoder_cmd(struct file *file, void *fh,
1049                             struct v4l2_encoder_cmd *ec)
1050 {
1051         struct vicodec_ctx *ctx = file2ctx(file);
1052         int ret;
1053
1054         ret = vicodec_try_encoder_cmd(file, fh, ec);
1055         if (ret < 0)
1056                 return ret;
1057
1058         vicodec_mark_last_buf(ctx);
1059         return 0;
1060 }
1061
1062 static int vicodec_try_decoder_cmd(struct file *file, void *fh,
1063                                 struct v4l2_decoder_cmd *dc)
1064 {
1065         if (dc->cmd != V4L2_DEC_CMD_STOP)
1066                 return -EINVAL;
1067
1068         if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
1069                 return -EINVAL;
1070
1071         if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
1072                 return -EINVAL;
1073
1074         return 0;
1075 }
1076
1077 static int vicodec_decoder_cmd(struct file *file, void *fh,
1078                             struct v4l2_decoder_cmd *dc)
1079 {
1080         struct vicodec_ctx *ctx = file2ctx(file);
1081         int ret;
1082
1083         ret = vicodec_try_decoder_cmd(file, fh, dc);
1084         if (ret < 0)
1085                 return ret;
1086
1087         vicodec_mark_last_buf(ctx);
1088         return 0;
1089 }
1090
1091 static int vicodec_enum_framesizes(struct file *file, void *fh,
1092                                    struct v4l2_frmsizeenum *fsize)
1093 {
1094         switch (fsize->pixel_format) {
1095         case V4L2_PIX_FMT_FWHT:
1096                 break;
1097         default:
1098                 if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
1099                         break;
1100                 return -EINVAL;
1101         }
1102
1103         if (fsize->index)
1104                 return -EINVAL;
1105
1106         fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
1107
1108         fsize->stepwise.min_width = MIN_WIDTH;
1109         fsize->stepwise.max_width = MAX_WIDTH;
1110         fsize->stepwise.step_width = 8;
1111         fsize->stepwise.min_height = MIN_HEIGHT;
1112         fsize->stepwise.max_height = MAX_HEIGHT;
1113         fsize->stepwise.step_height = 8;
1114
1115         return 0;
1116 }
1117
1118 static int vicodec_subscribe_event(struct v4l2_fh *fh,
1119                                 const struct v4l2_event_subscription *sub)
1120 {
1121         struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh);
1122
1123         switch (sub->type) {
1124         case V4L2_EVENT_SOURCE_CHANGE:
1125                 if (ctx->is_enc)
1126                         return -EINVAL;
1127                 /* fall through */
1128         case V4L2_EVENT_EOS:
1129                 return v4l2_event_subscribe(fh, sub, 0, NULL);
1130         default:
1131                 return v4l2_ctrl_subscribe_event(fh, sub);
1132         }
1133 }
1134
1135 static const struct v4l2_ioctl_ops vicodec_ioctl_ops = {
1136         .vidioc_querycap        = vidioc_querycap,
1137
1138         .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1139         .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
1140         .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1141         .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
1142
1143         .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
1144         .vidioc_g_fmt_vid_cap_mplane    = vidioc_g_fmt_vid_cap,
1145         .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap,
1146         .vidioc_s_fmt_vid_cap_mplane    = vidioc_s_fmt_vid_cap,
1147
1148         .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1149         .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
1150         .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1151         .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
1152
1153         .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
1154         .vidioc_g_fmt_vid_out_mplane    = vidioc_g_fmt_vid_out,
1155         .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out,
1156         .vidioc_s_fmt_vid_out_mplane    = vidioc_s_fmt_vid_out,
1157
1158         .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
1159         .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
1160         .vidioc_qbuf            = v4l2_m2m_ioctl_qbuf,
1161         .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
1162         .vidioc_prepare_buf     = v4l2_m2m_ioctl_prepare_buf,
1163         .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
1164         .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
1165
1166         .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
1167         .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
1168
1169         .vidioc_g_selection     = vidioc_g_selection,
1170         .vidioc_s_selection     = vidioc_s_selection,
1171
1172         .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd,
1173         .vidioc_encoder_cmd     = vicodec_encoder_cmd,
1174         .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd,
1175         .vidioc_decoder_cmd     = vicodec_decoder_cmd,
1176         .vidioc_enum_framesizes = vicodec_enum_framesizes,
1177
1178         .vidioc_subscribe_event = vicodec_subscribe_event,
1179         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1180 };
1181
1182
1183 /*
1184  * Queue operations
1185  */
1186
1187 static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1188                                unsigned int *nplanes, unsigned int sizes[],
1189                                struct device *alloc_devs[])
1190 {
1191         struct vicodec_ctx *ctx = vb2_get_drv_priv(vq);
1192         struct vicodec_q_data *q_data = get_q_data(ctx, vq->type);
1193         unsigned int size = q_data->sizeimage;
1194
1195         if (*nplanes)
1196                 return sizes[0] < size ? -EINVAL : 0;
1197
1198         *nplanes = 1;
1199         sizes[0] = size;
1200         return 0;
1201 }
1202
1203 static int vicodec_buf_prepare(struct vb2_buffer *vb)
1204 {
1205         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1206         struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1207         struct vicodec_q_data *q_data;
1208
1209         dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
1210
1211         q_data = get_q_data(ctx, vb->vb2_queue->type);
1212         if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1213                 if (vbuf->field == V4L2_FIELD_ANY)
1214                         vbuf->field = V4L2_FIELD_NONE;
1215                 if (vbuf->field != V4L2_FIELD_NONE) {
1216                         dprintk(ctx->dev, "%s field isn't supported\n",
1217                                         __func__);
1218                         return -EINVAL;
1219                 }
1220         }
1221
1222         if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
1223                 dprintk(ctx->dev,
1224                         "%s data will not fit into plane (%lu < %lu)\n",
1225                         __func__, vb2_plane_size(vb, 0),
1226                         (long)q_data->sizeimage);
1227                 return -EINVAL;
1228         }
1229
1230         return 0;
1231 }
1232
1233 static void vicodec_buf_queue(struct vb2_buffer *vb)
1234 {
1235         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1236         struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1237         unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
1238         u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
1239         u8 *p = p_src;
1240         struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1241                                                    V4L2_BUF_TYPE_VIDEO_OUTPUT);
1242         struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
1243                                                    V4L2_BUF_TYPE_VIDEO_CAPTURE);
1244         bool header_valid = false;
1245         static const struct v4l2_event rs_event = {
1246                 .type = V4L2_EVENT_SOURCE_CHANGE,
1247                 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
1248         };
1249
1250         /* buf_queue handles only the first source change event */
1251         if (ctx->first_source_change_sent) {
1252                 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1253                 return;
1254         }
1255
1256         /*
1257          * if both queues are streaming, the source change event is
1258          * handled in job_ready
1259          */
1260         if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) {
1261                 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1262                 return;
1263         }
1264
1265         /*
1266          * source change event is relevant only for the decoder
1267          * in the compressed stream
1268          */
1269         if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
1270                 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1271                 return;
1272         }
1273
1274         do {
1275                 enum vb2_buffer_state state =
1276                         get_next_header(ctx, &p, p_src + sz - p);
1277
1278                 if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
1279                         v4l2_m2m_buf_done(vbuf, state);
1280                         return;
1281                 }
1282                 header_valid = is_header_valid(&ctx->state.header);
1283                 /*
1284                  * p points right after the end of the header in the
1285                  * buffer. If the header is invalid we set p to point
1286                  * to the next byte after the start of the header
1287                  */
1288                 if (!header_valid) {
1289                         p = p - sizeof(struct fwht_cframe_hdr) + 1;
1290                         if (p < p_src)
1291                                 p = p_src;
1292                         ctx->header_size = 0;
1293                         ctx->comp_magic_cnt = 0;
1294                 }
1295
1296         } while (!header_valid);
1297
1298         ctx->cur_buf_offset = p - p_src;
1299         update_capture_data_from_header(ctx);
1300         ctx->first_source_change_sent = true;
1301         v4l2_event_queue_fh(&ctx->fh, &rs_event);
1302         v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1303 }
1304
1305 static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
1306 {
1307         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1308         struct vb2_v4l2_buffer *vbuf;
1309
1310         for (;;) {
1311                 if (V4L2_TYPE_IS_OUTPUT(q->type))
1312                         vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1313                 else
1314                         vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1315                 if (vbuf == NULL)
1316                         return;
1317                 spin_lock(ctx->lock);
1318                 v4l2_m2m_buf_done(vbuf, state);
1319                 spin_unlock(ctx->lock);
1320         }
1321 }
1322
1323 static int vicodec_start_streaming(struct vb2_queue *q,
1324                                    unsigned int count)
1325 {
1326         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1327         struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
1328         struct v4l2_fwht_state *state = &ctx->state;
1329         const struct v4l2_fwht_pixfmt_info *info = q_data->info;
1330         unsigned int size = q_data->coded_width * q_data->coded_height;
1331         unsigned int chroma_div;
1332         unsigned int total_planes_size;
1333         u8 *new_comp_frame;
1334
1335         if (!info)
1336                 return -EINVAL;
1337
1338         chroma_div = info->width_div * info->height_div;
1339         q_data->sequence = 0;
1340
1341         ctx->last_src_buf = NULL;
1342         ctx->last_dst_buf = NULL;
1343         state->gop_cnt = 0;
1344
1345         if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1346             (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc))
1347                 return 0;
1348
1349         if (info->id == V4L2_PIX_FMT_FWHT) {
1350                 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1351                 return -EINVAL;
1352         }
1353         if (info->components_num == 4)
1354                 total_planes_size = 2 * size + 2 * (size / chroma_div);
1355         else if (info->components_num == 3)
1356                 total_planes_size = size + 2 * (size / chroma_div);
1357         else
1358                 total_planes_size = size;
1359
1360         state->visible_width = q_data->visible_width;
1361         state->visible_height = q_data->visible_height;
1362         state->coded_width = q_data->coded_width;
1363         state->coded_height = q_data->coded_height;
1364         state->stride = q_data->coded_width *
1365                                 info->bytesperline_mult;
1366
1367         state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL);
1368         ctx->comp_max_size = total_planes_size;
1369         new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
1370
1371         if (!state->ref_frame.luma || !new_comp_frame) {
1372                 kvfree(state->ref_frame.luma);
1373                 kvfree(new_comp_frame);
1374                 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
1375                 return -ENOMEM;
1376         }
1377         /*
1378          * if state->compressed_frame was already allocated then
1379          * it contain data of the first frame of the new resolution
1380          */
1381         if (state->compressed_frame) {
1382                 if (ctx->comp_size > ctx->comp_max_size)
1383                         ctx->comp_size = ctx->comp_max_size;
1384
1385                 memcpy(new_comp_frame,
1386                        state->compressed_frame, ctx->comp_size);
1387         }
1388
1389         kvfree(state->compressed_frame);
1390         state->compressed_frame = new_comp_frame;
1391
1392         if (info->components_num >= 3) {
1393                 state->ref_frame.cb = state->ref_frame.luma + size;
1394                 state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
1395         } else {
1396                 state->ref_frame.cb = NULL;
1397                 state->ref_frame.cr = NULL;
1398         }
1399
1400         if (info->components_num == 4)
1401                 state->ref_frame.alpha =
1402                         state->ref_frame.cr + size / chroma_div;
1403         else
1404                 state->ref_frame.alpha = NULL;
1405         return 0;
1406 }
1407
1408 static void vicodec_stop_streaming(struct vb2_queue *q)
1409 {
1410         struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
1411
1412         vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
1413
1414         if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
1415             (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) {
1416                 kvfree(ctx->state.ref_frame.luma);
1417                 ctx->comp_max_size = 0;
1418                 ctx->source_changed = false;
1419         }
1420         if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) {
1421                 ctx->cur_buf_offset = 0;
1422                 ctx->comp_size = 0;
1423                 ctx->header_size = 0;
1424                 ctx->comp_magic_cnt = 0;
1425                 ctx->comp_has_frame = 0;
1426                 ctx->comp_has_next_frame = 0;
1427         }
1428 }
1429
1430 static const struct vb2_ops vicodec_qops = {
1431         .queue_setup     = vicodec_queue_setup,
1432         .buf_prepare     = vicodec_buf_prepare,
1433         .buf_queue       = vicodec_buf_queue,
1434         .start_streaming = vicodec_start_streaming,
1435         .stop_streaming  = vicodec_stop_streaming,
1436         .wait_prepare    = vb2_ops_wait_prepare,
1437         .wait_finish     = vb2_ops_wait_finish,
1438 };
1439
1440 static int queue_init(void *priv, struct vb2_queue *src_vq,
1441                       struct vb2_queue *dst_vq)
1442 {
1443         struct vicodec_ctx *ctx = priv;
1444         int ret;
1445
1446         src_vq->type = (multiplanar ?
1447                         V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1448                         V4L2_BUF_TYPE_VIDEO_OUTPUT);
1449         src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1450         src_vq->drv_priv = ctx;
1451         src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1452         src_vq->ops = &vicodec_qops;
1453         src_vq->mem_ops = &vb2_vmalloc_memops;
1454         src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1455         src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex :
1456                 &ctx->dev->dec_mutex;
1457
1458         ret = vb2_queue_init(src_vq);
1459         if (ret)
1460                 return ret;
1461
1462         dst_vq->type = (multiplanar ?
1463                         V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1464                         V4L2_BUF_TYPE_VIDEO_CAPTURE);
1465         dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1466         dst_vq->drv_priv = ctx;
1467         dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1468         dst_vq->ops = &vicodec_qops;
1469         dst_vq->mem_ops = &vb2_vmalloc_memops;
1470         dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1471         dst_vq->lock = src_vq->lock;
1472
1473         return vb2_queue_init(dst_vq);
1474 }
1475
1476 #define VICODEC_CID_CUSTOM_BASE         (V4L2_CID_MPEG_BASE | 0xf000)
1477 #define VICODEC_CID_I_FRAME_QP          (VICODEC_CID_CUSTOM_BASE + 0)
1478 #define VICODEC_CID_P_FRAME_QP          (VICODEC_CID_CUSTOM_BASE + 1)
1479
1480 static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
1481 {
1482         struct vicodec_ctx *ctx = container_of(ctrl->handler,
1483                                                struct vicodec_ctx, hdl);
1484
1485         switch (ctrl->id) {
1486         case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
1487                 ctx->state.gop_size = ctrl->val;
1488                 return 0;
1489         case VICODEC_CID_I_FRAME_QP:
1490                 ctx->state.i_frame_qp = ctrl->val;
1491                 return 0;
1492         case VICODEC_CID_P_FRAME_QP:
1493                 ctx->state.p_frame_qp = ctrl->val;
1494                 return 0;
1495         }
1496         return -EINVAL;
1497 }
1498
1499 static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
1500         .s_ctrl = vicodec_s_ctrl,
1501 };
1502
1503 static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
1504         .ops = &vicodec_ctrl_ops,
1505         .id = VICODEC_CID_I_FRAME_QP,
1506         .name = "FWHT I-Frame QP Value",
1507         .type = V4L2_CTRL_TYPE_INTEGER,
1508         .min = 1,
1509         .max = 31,
1510         .def = 20,
1511         .step = 1,
1512 };
1513
1514 static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
1515         .ops = &vicodec_ctrl_ops,
1516         .id = VICODEC_CID_P_FRAME_QP,
1517         .name = "FWHT P-Frame QP Value",
1518         .type = V4L2_CTRL_TYPE_INTEGER,
1519         .min = 1,
1520         .max = 31,
1521         .def = 20,
1522         .step = 1,
1523 };
1524
1525 /*
1526  * File operations
1527  */
1528 static int vicodec_open(struct file *file)
1529 {
1530         struct video_device *vfd = video_devdata(file);
1531         struct vicodec_dev *dev = video_drvdata(file);
1532         struct vicodec_ctx *ctx = NULL;
1533         struct v4l2_ctrl_handler *hdl;
1534         unsigned int size;
1535         int rc = 0;
1536
1537         if (mutex_lock_interruptible(vfd->lock))
1538                 return -ERESTARTSYS;
1539         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1540         if (!ctx) {
1541                 rc = -ENOMEM;
1542                 goto open_unlock;
1543         }
1544
1545         if (vfd == &dev->enc_vfd)
1546                 ctx->is_enc = true;
1547
1548         v4l2_fh_init(&ctx->fh, video_devdata(file));
1549         file->private_data = &ctx->fh;
1550         ctx->dev = dev;
1551         hdl = &ctx->hdl;
1552         v4l2_ctrl_handler_init(hdl, 4);
1553         v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1554                           1, 16, 1, 10);
1555         v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
1556         v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
1557         if (hdl->error) {
1558                 rc = hdl->error;
1559                 v4l2_ctrl_handler_free(hdl);
1560                 kfree(ctx);
1561                 goto open_unlock;
1562         }
1563         ctx->fh.ctrl_handler = hdl;
1564         v4l2_ctrl_handler_setup(hdl);
1565
1566         ctx->q_data[V4L2_M2M_SRC].info =
1567                 ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
1568         ctx->q_data[V4L2_M2M_SRC].coded_width = 1280;
1569         ctx->q_data[V4L2_M2M_SRC].coded_height = 720;
1570         ctx->q_data[V4L2_M2M_SRC].visible_width = 1280;
1571         ctx->q_data[V4L2_M2M_SRC].visible_height = 720;
1572         size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
1573                 ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
1574         if (ctx->is_enc)
1575                 ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
1576         else
1577                 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1578                         size + sizeof(struct fwht_cframe_hdr);
1579         if (ctx->is_enc) {
1580                 ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1581                 ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht;
1582                 ctx->q_data[V4L2_M2M_DST].sizeimage = 1280 * 720 *
1583                         ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
1584                         ctx->q_data[V4L2_M2M_DST].info->sizeimage_div +
1585                         sizeof(struct fwht_cframe_hdr);
1586         } else {
1587                 ctx->q_data[V4L2_M2M_DST].info = NULL;
1588         }
1589
1590         ctx->state.colorspace = V4L2_COLORSPACE_REC709;
1591
1592         if (ctx->is_enc) {
1593                 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
1594                                                     &queue_init);
1595                 ctx->lock = &dev->enc_lock;
1596         } else {
1597                 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
1598                                                     &queue_init);
1599                 ctx->lock = &dev->dec_lock;
1600         }
1601
1602         if (IS_ERR(ctx->fh.m2m_ctx)) {
1603                 rc = PTR_ERR(ctx->fh.m2m_ctx);
1604
1605                 v4l2_ctrl_handler_free(hdl);
1606                 v4l2_fh_exit(&ctx->fh);
1607                 kfree(ctx);
1608                 goto open_unlock;
1609         }
1610
1611         v4l2_fh_add(&ctx->fh);
1612
1613 open_unlock:
1614         mutex_unlock(vfd->lock);
1615         return rc;
1616 }
1617
1618 static int vicodec_release(struct file *file)
1619 {
1620         struct video_device *vfd = video_devdata(file);
1621         struct vicodec_ctx *ctx = file2ctx(file);
1622
1623         v4l2_fh_del(&ctx->fh);
1624         v4l2_fh_exit(&ctx->fh);
1625         v4l2_ctrl_handler_free(&ctx->hdl);
1626         mutex_lock(vfd->lock);
1627         v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1628         mutex_unlock(vfd->lock);
1629         kfree(ctx);
1630
1631         return 0;
1632 }
1633
1634 static const struct v4l2_file_operations vicodec_fops = {
1635         .owner          = THIS_MODULE,
1636         .open           = vicodec_open,
1637         .release        = vicodec_release,
1638         .poll           = v4l2_m2m_fop_poll,
1639         .unlocked_ioctl = video_ioctl2,
1640         .mmap           = v4l2_m2m_fop_mmap,
1641 };
1642
1643 static const struct video_device vicodec_videodev = {
1644         .name           = VICODEC_NAME,
1645         .vfl_dir        = VFL_DIR_M2M,
1646         .fops           = &vicodec_fops,
1647         .ioctl_ops      = &vicodec_ioctl_ops,
1648         .minor          = -1,
1649         .release        = video_device_release_empty,
1650 };
1651
1652 static const struct v4l2_m2m_ops m2m_ops = {
1653         .device_run     = device_run,
1654         .job_ready      = job_ready,
1655 };
1656
1657 static int vicodec_probe(struct platform_device *pdev)
1658 {
1659         struct vicodec_dev *dev;
1660         struct video_device *vfd;
1661         int ret;
1662
1663         dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1664         if (!dev)
1665                 return -ENOMEM;
1666
1667         spin_lock_init(&dev->enc_lock);
1668         spin_lock_init(&dev->dec_lock);
1669
1670         ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1671         if (ret)
1672                 return ret;
1673
1674 #ifdef CONFIG_MEDIA_CONTROLLER
1675         dev->mdev.dev = &pdev->dev;
1676         strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
1677         strscpy(dev->mdev.bus_info, "platform:vicodec",
1678                 sizeof(dev->mdev.bus_info));
1679         media_device_init(&dev->mdev);
1680         dev->v4l2_dev.mdev = &dev->mdev;
1681 #endif
1682
1683         mutex_init(&dev->enc_mutex);
1684         mutex_init(&dev->dec_mutex);
1685
1686         platform_set_drvdata(pdev, dev);
1687
1688         dev->enc_dev = v4l2_m2m_init(&m2m_ops);
1689         if (IS_ERR(dev->enc_dev)) {
1690                 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1691                 ret = PTR_ERR(dev->enc_dev);
1692                 goto unreg_dev;
1693         }
1694
1695         dev->dec_dev = v4l2_m2m_init(&m2m_ops);
1696         if (IS_ERR(dev->dec_dev)) {
1697                 v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
1698                 ret = PTR_ERR(dev->dec_dev);
1699                 goto err_enc_m2m;
1700         }
1701
1702         dev->enc_vfd = vicodec_videodev;
1703         vfd = &dev->enc_vfd;
1704         vfd->lock = &dev->enc_mutex;
1705         vfd->v4l2_dev = &dev->v4l2_dev;
1706         strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
1707         vfd->device_caps = V4L2_CAP_STREAMING |
1708                 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1709         v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
1710         v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
1711         video_set_drvdata(vfd, dev);
1712
1713         ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1714         if (ret) {
1715                 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1716                 goto err_dec_m2m;
1717         }
1718         v4l2_info(&dev->v4l2_dev,
1719                         "Device registered as /dev/video%d\n", vfd->num);
1720
1721         dev->dec_vfd = vicodec_videodev;
1722         vfd = &dev->dec_vfd;
1723         vfd->lock = &dev->dec_mutex;
1724         vfd->v4l2_dev = &dev->v4l2_dev;
1725         vfd->device_caps = V4L2_CAP_STREAMING |
1726                 (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
1727         strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
1728         v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
1729         v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
1730         video_set_drvdata(vfd, dev);
1731
1732         ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1733         if (ret) {
1734                 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1735                 goto unreg_enc;
1736         }
1737         v4l2_info(&dev->v4l2_dev,
1738                         "Device registered as /dev/video%d\n", vfd->num);
1739
1740 #ifdef CONFIG_MEDIA_CONTROLLER
1741         ret = v4l2_m2m_register_media_controller(dev->enc_dev,
1742                         &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
1743         if (ret) {
1744                 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1745                 goto unreg_m2m;
1746         }
1747
1748         ret = v4l2_m2m_register_media_controller(dev->dec_dev,
1749                         &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER);
1750         if (ret) {
1751                 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1752                 goto unreg_m2m_enc_mc;
1753         }
1754
1755         ret = media_device_register(&dev->mdev);
1756         if (ret) {
1757                 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1758                 goto unreg_m2m_dec_mc;
1759         }
1760 #endif
1761         return 0;
1762
1763 #ifdef CONFIG_MEDIA_CONTROLLER
1764 unreg_m2m_dec_mc:
1765         v4l2_m2m_unregister_media_controller(dev->dec_dev);
1766 unreg_m2m_enc_mc:
1767         v4l2_m2m_unregister_media_controller(dev->enc_dev);
1768 unreg_m2m:
1769         video_unregister_device(&dev->dec_vfd);
1770 #endif
1771 unreg_enc:
1772         video_unregister_device(&dev->enc_vfd);
1773 err_dec_m2m:
1774         v4l2_m2m_release(dev->dec_dev);
1775 err_enc_m2m:
1776         v4l2_m2m_release(dev->enc_dev);
1777 unreg_dev:
1778         v4l2_device_unregister(&dev->v4l2_dev);
1779
1780         return ret;
1781 }
1782
1783 static int vicodec_remove(struct platform_device *pdev)
1784 {
1785         struct vicodec_dev *dev = platform_get_drvdata(pdev);
1786
1787         v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME);
1788
1789 #ifdef CONFIG_MEDIA_CONTROLLER
1790         media_device_unregister(&dev->mdev);
1791         v4l2_m2m_unregister_media_controller(dev->enc_dev);
1792         v4l2_m2m_unregister_media_controller(dev->dec_dev);
1793         media_device_cleanup(&dev->mdev);
1794 #endif
1795
1796         v4l2_m2m_release(dev->enc_dev);
1797         v4l2_m2m_release(dev->dec_dev);
1798         video_unregister_device(&dev->enc_vfd);
1799         video_unregister_device(&dev->dec_vfd);
1800         v4l2_device_unregister(&dev->v4l2_dev);
1801
1802         return 0;
1803 }
1804
1805 static struct platform_driver vicodec_pdrv = {
1806         .probe          = vicodec_probe,
1807         .remove         = vicodec_remove,
1808         .driver         = {
1809                 .name   = VICODEC_NAME,
1810         },
1811 };
1812
1813 static void __exit vicodec_exit(void)
1814 {
1815         platform_driver_unregister(&vicodec_pdrv);
1816         platform_device_unregister(&vicodec_pdev);
1817 }
1818
1819 static int __init vicodec_init(void)
1820 {
1821         int ret;
1822
1823         ret = platform_device_register(&vicodec_pdev);
1824         if (ret)
1825                 return ret;
1826
1827         ret = platform_driver_register(&vicodec_pdrv);
1828         if (ret)
1829                 platform_device_unregister(&vicodec_pdev);
1830
1831         return ret;
1832 }
1833
1834 module_init(vicodec_init);
1835 module_exit(vicodec_exit);