GNU Linux-libre 5.10.219-gnu1
[releases.git] / drivers / media / test-drivers / vim2m.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * A virtual v4l2-mem2mem example device.
4  *
5  * This is a virtual device driver for testing mem-to-mem videobuf framework.
6  * It simulates a device that uses memory buffers for both source and
7  * destination, processes the data and issues an "irq" (simulated by a delayed
8  * workqueue).
9  * The device is capable of multi-instance, multi-buffer-per-transaction
10  * operation (via the mem2mem framework).
11  *
12  * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
13  * Pawel Osciak, <pawel@osciak.com>
14  * Marek Szyprowski, <m.szyprowski@samsung.com>
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by the
18  * Free Software Foundation; either version 2 of the
19  * License, or (at your option) any later version
20  */
21 #include <linux/module.h>
22 #include <linux/delay.h>
23 #include <linux/fs.h>
24 #include <linux/sched.h>
25 #include <linux/slab.h>
26
27 #include <linux/platform_device.h>
28 #include <media/v4l2-mem2mem.h>
29 #include <media/v4l2-device.h>
30 #include <media/v4l2-ioctl.h>
31 #include <media/v4l2-ctrls.h>
32 #include <media/v4l2-event.h>
33 #include <media/videobuf2-vmalloc.h>
34
35 MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
36 MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
37 MODULE_LICENSE("GPL");
38 MODULE_VERSION("0.2");
39 MODULE_ALIAS("mem2mem_testdev");
40
41 static unsigned int debug;
42 module_param(debug, uint, 0644);
43 MODULE_PARM_DESC(debug, "debug level");
44
45 /* Default transaction time in msec */
46 static unsigned int default_transtime = 40; /* Max 25 fps */
47 module_param(default_transtime, uint, 0644);
48 MODULE_PARM_DESC(default_transtime, "default transaction time in ms");
49
50 #define MIN_W 32
51 #define MIN_H 32
52 #define MAX_W 640
53 #define MAX_H 480
54
55 /* Pixel alignment for non-bayer formats */
56 #define WIDTH_ALIGN 2
57 #define HEIGHT_ALIGN 1
58
59 /* Pixel alignment for bayer formats */
60 #define BAYER_WIDTH_ALIGN  2
61 #define BAYER_HEIGHT_ALIGN 2
62
63 /* Flags that indicate a format can be used for capture/output */
64 #define MEM2MEM_CAPTURE BIT(0)
65 #define MEM2MEM_OUTPUT  BIT(1)
66
67 #define MEM2MEM_NAME            "vim2m"
68
69 /* Per queue */
70 #define MEM2MEM_DEF_NUM_BUFS    VIDEO_MAX_FRAME
71 /* In bytes, per queue */
72 #define MEM2MEM_VID_MEM_LIMIT   (16 * 1024 * 1024)
73
74 /* Flags that indicate processing mode */
75 #define MEM2MEM_HFLIP   BIT(0)
76 #define MEM2MEM_VFLIP   BIT(1)
77
78 #define dprintk(dev, lvl, fmt, arg...) \
79         v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg)
80
81 static void vim2m_dev_release(struct device *dev)
82 {}
83
84 static struct platform_device vim2m_pdev = {
85         .name           = MEM2MEM_NAME,
86         .dev.release    = vim2m_dev_release,
87 };
88
89 struct vim2m_fmt {
90         u32     fourcc;
91         int     depth;
92         /* Types the format can be used for */
93         u32     types;
94 };
95
96 static struct vim2m_fmt formats[] = {
97         {
98                 .fourcc = V4L2_PIX_FMT_RGB565,  /* rrrrrggg gggbbbbb */
99                 .depth  = 16,
100                 .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
101         }, {
102                 .fourcc = V4L2_PIX_FMT_RGB565X, /* gggbbbbb rrrrrggg */
103                 .depth  = 16,
104                 .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
105         }, {
106                 .fourcc = V4L2_PIX_FMT_RGB24,
107                 .depth  = 24,
108                 .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
109         }, {
110                 .fourcc = V4L2_PIX_FMT_BGR24,
111                 .depth  = 24,
112                 .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
113         }, {
114                 .fourcc = V4L2_PIX_FMT_YUYV,
115                 .depth  = 16,
116                 .types  = MEM2MEM_CAPTURE,
117         }, {
118                 .fourcc = V4L2_PIX_FMT_SBGGR8,
119                 .depth  = 8,
120                 .types  = MEM2MEM_CAPTURE,
121         }, {
122                 .fourcc = V4L2_PIX_FMT_SGBRG8,
123                 .depth  = 8,
124                 .types  = MEM2MEM_CAPTURE,
125         }, {
126                 .fourcc = V4L2_PIX_FMT_SGRBG8,
127                 .depth  = 8,
128                 .types  = MEM2MEM_CAPTURE,
129         }, {
130                 .fourcc = V4L2_PIX_FMT_SRGGB8,
131                 .depth  = 8,
132                 .types  = MEM2MEM_CAPTURE,
133         },
134 };
135
136 #define NUM_FORMATS ARRAY_SIZE(formats)
137
138 /* Per-queue, driver-specific private data */
139 struct vim2m_q_data {
140         unsigned int            width;
141         unsigned int            height;
142         unsigned int            sizeimage;
143         unsigned int            sequence;
144         struct vim2m_fmt        *fmt;
145 };
146
147 enum {
148         V4L2_M2M_SRC = 0,
149         V4L2_M2M_DST = 1,
150 };
151
152 #define V4L2_CID_TRANS_TIME_MSEC        (V4L2_CID_USER_BASE + 0x1000)
153 #define V4L2_CID_TRANS_NUM_BUFS         (V4L2_CID_USER_BASE + 0x1001)
154
155 static struct vim2m_fmt *find_format(u32 fourcc)
156 {
157         struct vim2m_fmt *fmt;
158         unsigned int k;
159
160         for (k = 0; k < NUM_FORMATS; k++) {
161                 fmt = &formats[k];
162                 if (fmt->fourcc == fourcc)
163                         break;
164         }
165
166         if (k == NUM_FORMATS)
167                 return NULL;
168
169         return &formats[k];
170 }
171
172 static void get_alignment(u32 fourcc,
173                           unsigned int *walign, unsigned int *halign)
174 {
175         switch (fourcc) {
176         case V4L2_PIX_FMT_SBGGR8:
177         case V4L2_PIX_FMT_SGBRG8:
178         case V4L2_PIX_FMT_SGRBG8:
179         case V4L2_PIX_FMT_SRGGB8:
180                 *walign = BAYER_WIDTH_ALIGN;
181                 *halign = BAYER_HEIGHT_ALIGN;
182                 return;
183         default:
184                 *walign = WIDTH_ALIGN;
185                 *halign = HEIGHT_ALIGN;
186                 return;
187         }
188 }
189
190 struct vim2m_dev {
191         struct v4l2_device      v4l2_dev;
192         struct video_device     vfd;
193 #ifdef CONFIG_MEDIA_CONTROLLER
194         struct media_device     mdev;
195 #endif
196
197         atomic_t                num_inst;
198         struct mutex            dev_mutex;
199
200         struct v4l2_m2m_dev     *m2m_dev;
201 };
202
203 struct vim2m_ctx {
204         struct v4l2_fh          fh;
205         struct vim2m_dev        *dev;
206
207         struct v4l2_ctrl_handler hdl;
208
209         /* Processed buffers in this transaction */
210         u8                      num_processed;
211
212         /* Transaction length (i.e. how many buffers per transaction) */
213         u32                     translen;
214         /* Transaction time (i.e. simulated processing time) in milliseconds */
215         u32                     transtime;
216
217         struct mutex            vb_mutex;
218         struct delayed_work     work_run;
219
220         /* Abort requested by m2m */
221         int                     aborting;
222
223         /* Processing mode */
224         int                     mode;
225
226         enum v4l2_colorspace    colorspace;
227         enum v4l2_ycbcr_encoding ycbcr_enc;
228         enum v4l2_xfer_func     xfer_func;
229         enum v4l2_quantization  quant;
230
231         /* Source and destination queue data */
232         struct vim2m_q_data   q_data[2];
233 };
234
235 static inline struct vim2m_ctx *file2ctx(struct file *file)
236 {
237         return container_of(file->private_data, struct vim2m_ctx, fh);
238 }
239
240 static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx,
241                                        enum v4l2_buf_type type)
242 {
243         switch (type) {
244         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
245                 return &ctx->q_data[V4L2_M2M_SRC];
246         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
247                 return &ctx->q_data[V4L2_M2M_DST];
248         default:
249                 return NULL;
250         }
251 }
252
253 static const char *type_name(enum v4l2_buf_type type)
254 {
255         switch (type) {
256         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
257                 return "Output";
258         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
259                 return "Capture";
260         default:
261                 return "Invalid";
262         }
263 }
264
265 #define CLIP(__color) \
266         (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color)))
267
268 static void copy_line(struct vim2m_q_data *q_data_out,
269                       u8 *src, u8 *dst, bool reverse)
270 {
271         int x, depth = q_data_out->fmt->depth >> 3;
272
273         if (!reverse) {
274                 memcpy(dst, src, q_data_out->width * depth);
275         } else {
276                 for (x = 0; x < q_data_out->width >> 1; x++) {
277                         memcpy(dst, src, depth);
278                         memcpy(dst + depth, src - depth, depth);
279                         src -= depth << 1;
280                         dst += depth << 1;
281                 }
282                 return;
283         }
284 }
285
286 static void copy_two_pixels(struct vim2m_q_data *q_data_in,
287                             struct vim2m_q_data *q_data_out,
288                             u8 *src[2], u8 **dst, int ypos, bool reverse)
289 {
290         struct vim2m_fmt *out = q_data_out->fmt;
291         struct vim2m_fmt *in = q_data_in->fmt;
292         u8 _r[2], _g[2], _b[2], *r, *g, *b;
293         int i;
294
295         /* Step 1: read two consecutive pixels from src pointer */
296
297         r = _r;
298         g = _g;
299         b = _b;
300
301         switch (in->fourcc) {
302         case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
303                 for (i = 0; i < 2; i++) {
304                         u16 pix = le16_to_cpu(*(__le16 *)(src[i]));
305
306                         *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07;
307                         *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03;
308                         *b++ = (u8)((pix & 0x1f) << 3) | 0x07;
309                 }
310                 break;
311         case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
312                 for (i = 0; i < 2; i++) {
313                         u16 pix = be16_to_cpu(*(__be16 *)(src[i]));
314
315                         *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07;
316                         *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03;
317                         *b++ = (u8)((pix & 0x1f) << 3) | 0x07;
318                 }
319                 break;
320         default:
321         case V4L2_PIX_FMT_RGB24:
322                 for (i = 0; i < 2; i++) {
323                         *r++ = src[i][0];
324                         *g++ = src[i][1];
325                         *b++ = src[i][2];
326                 }
327                 break;
328         case V4L2_PIX_FMT_BGR24:
329                 for (i = 0; i < 2; i++) {
330                         *b++ = src[i][0];
331                         *g++ = src[i][1];
332                         *r++ = src[i][2];
333                 }
334                 break;
335         }
336
337         /* Step 2: store two consecutive points, reversing them if needed */
338
339         r = _r;
340         g = _g;
341         b = _b;
342
343         switch (out->fourcc) {
344         case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
345                 for (i = 0; i < 2; i++) {
346                         u16 pix;
347                         __le16 *dst_pix = (__le16 *)*dst;
348
349                         pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) |
350                               (*b >> 3);
351
352                         *dst_pix = cpu_to_le16(pix);
353
354                         *dst += 2;
355                 }
356                 return;
357         case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
358                 for (i = 0; i < 2; i++) {
359                         u16 pix;
360                         __be16 *dst_pix = (__be16 *)*dst;
361
362                         pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) |
363                               (*b >> 3);
364
365                         *dst_pix = cpu_to_be16(pix);
366
367                         *dst += 2;
368                 }
369                 return;
370         case V4L2_PIX_FMT_RGB24:
371                 for (i = 0; i < 2; i++) {
372                         *(*dst)++ = *r++;
373                         *(*dst)++ = *g++;
374                         *(*dst)++ = *b++;
375                 }
376                 return;
377         case V4L2_PIX_FMT_BGR24:
378                 for (i = 0; i < 2; i++) {
379                         *(*dst)++ = *b++;
380                         *(*dst)++ = *g++;
381                         *(*dst)++ = *r++;
382                 }
383                 return;
384         case V4L2_PIX_FMT_YUYV:
385         default:
386         {
387                 u8 y, y1, u, v;
388
389                 y = ((8453  * (*r) + 16594 * (*g) +  3223 * (*b)
390                      + 524288) >> 15);
391                 u = ((-4878 * (*r) - 9578  * (*g) + 14456 * (*b)
392                      + 4210688) >> 15);
393                 v = ((14456 * (*r++) - 12105 * (*g++) - 2351 * (*b++)
394                      + 4210688) >> 15);
395                 y1 = ((8453 * (*r) + 16594 * (*g) +  3223 * (*b)
396                      + 524288) >> 15);
397
398                 *(*dst)++ = y;
399                 *(*dst)++ = u;
400
401                 *(*dst)++ = y1;
402                 *(*dst)++ = v;
403                 return;
404         }
405         case V4L2_PIX_FMT_SBGGR8:
406                 if (!(ypos & 1)) {
407                         *(*dst)++ = *b;
408                         *(*dst)++ = *++g;
409                 } else {
410                         *(*dst)++ = *g;
411                         *(*dst)++ = *++r;
412                 }
413                 return;
414         case V4L2_PIX_FMT_SGBRG8:
415                 if (!(ypos & 1)) {
416                         *(*dst)++ = *g;
417                         *(*dst)++ = *++b;
418                 } else {
419                         *(*dst)++ = *r;
420                         *(*dst)++ = *++g;
421                 }
422                 return;
423         case V4L2_PIX_FMT_SGRBG8:
424                 if (!(ypos & 1)) {
425                         *(*dst)++ = *g;
426                         *(*dst)++ = *++r;
427                 } else {
428                         *(*dst)++ = *b;
429                         *(*dst)++ = *++g;
430                 }
431                 return;
432         case V4L2_PIX_FMT_SRGGB8:
433                 if (!(ypos & 1)) {
434                         *(*dst)++ = *r;
435                         *(*dst)++ = *++g;
436                 } else {
437                         *(*dst)++ = *g;
438                         *(*dst)++ = *++b;
439                 }
440                 return;
441         }
442 }
443
444 static int device_process(struct vim2m_ctx *ctx,
445                           struct vb2_v4l2_buffer *in_vb,
446                           struct vb2_v4l2_buffer *out_vb)
447 {
448         struct vim2m_dev *dev = ctx->dev;
449         struct vim2m_q_data *q_data_in, *q_data_out;
450         u8 *p_in, *p_line, *p_in_x[2], *p, *p_out;
451         unsigned int width, height, bytesperline, bytes_per_pixel;
452         unsigned int x, y, y_in, y_out, x_int, x_fract, x_err, x_offset;
453         int start, end, step;
454
455         q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
456         if (!q_data_in)
457                 return 0;
458         bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3;
459         bytes_per_pixel = q_data_in->fmt->depth >> 3;
460
461         q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
462         if (!q_data_out)
463                 return 0;
464
465         /* As we're doing scaling, use the output dimensions here */
466         height = q_data_out->height;
467         width = q_data_out->width;
468
469         p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
470         p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
471         if (!p_in || !p_out) {
472                 v4l2_err(&dev->v4l2_dev,
473                          "Acquiring kernel pointers to buffers failed\n");
474                 return -EFAULT;
475         }
476
477         out_vb->sequence = q_data_out->sequence++;
478         in_vb->sequence = q_data_in->sequence++;
479         v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true);
480
481         if (ctx->mode & MEM2MEM_VFLIP) {
482                 start = height - 1;
483                 end = -1;
484                 step = -1;
485         } else {
486                 start = 0;
487                 end = height;
488                 step = 1;
489         }
490         y_out = 0;
491
492         /*
493          * When format and resolution are identical,
494          * we can use a faster copy logic
495          */
496         if (q_data_in->fmt->fourcc == q_data_out->fmt->fourcc &&
497             q_data_in->width == q_data_out->width &&
498             q_data_in->height == q_data_out->height) {
499                 for (y = start; y != end; y += step, y_out++) {
500                         p = p_in + (y * bytesperline);
501                         if (ctx->mode & MEM2MEM_HFLIP)
502                                 p += bytesperline - (q_data_in->fmt->depth >> 3);
503
504                         copy_line(q_data_out, p, p_out,
505                                   ctx->mode & MEM2MEM_HFLIP);
506
507                         p_out += bytesperline;
508                 }
509                 return 0;
510         }
511
512         /* Slower algorithm with format conversion, hflip, vflip and scaler */
513
514         /* To speed scaler up, use Bresenham for X dimension */
515         x_int = q_data_in->width / q_data_out->width;
516         x_fract = q_data_in->width % q_data_out->width;
517
518         for (y = start; y != end; y += step, y_out++) {
519                 y_in = (y * q_data_in->height) / q_data_out->height;
520                 x_offset = 0;
521                 x_err = 0;
522
523                 p_line = p_in + (y_in * bytesperline);
524                 if (ctx->mode & MEM2MEM_HFLIP)
525                         p_line += bytesperline - (q_data_in->fmt->depth >> 3);
526                 p_in_x[0] = p_line;
527
528                 for (x = 0; x < width >> 1; x++) {
529                         x_offset += x_int;
530                         x_err += x_fract;
531                         if (x_err > width) {
532                                 x_offset++;
533                                 x_err -= width;
534                         }
535
536                         if (ctx->mode & MEM2MEM_HFLIP)
537                                 p_in_x[1] = p_line - x_offset * bytes_per_pixel;
538                         else
539                                 p_in_x[1] = p_line + x_offset * bytes_per_pixel;
540
541                         copy_two_pixels(q_data_in, q_data_out,
542                                         p_in_x, &p_out, y_out,
543                                         ctx->mode & MEM2MEM_HFLIP);
544
545                         /* Calculate the next p_in_x0 */
546                         x_offset += x_int;
547                         x_err += x_fract;
548                         if (x_err > width) {
549                                 x_offset++;
550                                 x_err -= width;
551                         }
552
553                         if (ctx->mode & MEM2MEM_HFLIP)
554                                 p_in_x[0] = p_line - x_offset * bytes_per_pixel;
555                         else
556                                 p_in_x[0] = p_line + x_offset * bytes_per_pixel;
557                 }
558         }
559
560         return 0;
561 }
562
563 /*
564  * mem2mem callbacks
565  */
566
567 /*
568  * job_ready() - check whether an instance is ready to be scheduled to run
569  */
570 static int job_ready(void *priv)
571 {
572         struct vim2m_ctx *ctx = priv;
573
574         if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen
575             || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) {
576                 dprintk(ctx->dev, 1, "Not enough buffers available\n");
577                 return 0;
578         }
579
580         return 1;
581 }
582
583 static void job_abort(void *priv)
584 {
585         struct vim2m_ctx *ctx = priv;
586
587         /* Will cancel the transaction in the next interrupt handler */
588         ctx->aborting = 1;
589 }
590
591 /* device_run() - prepares and starts the device
592  *
593  * This simulates all the immediate preparations required before starting
594  * a device. This will be called by the framework when it decides to schedule
595  * a particular instance.
596  */
597 static void device_run(void *priv)
598 {
599         struct vim2m_ctx *ctx = priv;
600         struct vb2_v4l2_buffer *src_buf, *dst_buf;
601
602         src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
603         dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
604
605         /* Apply request controls if any */
606         v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
607                                 &ctx->hdl);
608
609         device_process(ctx, src_buf, dst_buf);
610
611         /* Complete request controls if any */
612         v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
613                                    &ctx->hdl);
614
615         /* Run delayed work, which simulates a hardware irq  */
616         schedule_delayed_work(&ctx->work_run, msecs_to_jiffies(ctx->transtime));
617 }
618
619 static void device_work(struct work_struct *w)
620 {
621         struct vim2m_ctx *curr_ctx;
622         struct vim2m_dev *vim2m_dev;
623         struct vb2_v4l2_buffer *src_vb, *dst_vb;
624
625         curr_ctx = container_of(w, struct vim2m_ctx, work_run.work);
626
627         if (!curr_ctx) {
628                 pr_err("Instance released before the end of transaction\n");
629                 return;
630         }
631
632         vim2m_dev = curr_ctx->dev;
633
634         src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
635         dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
636
637         curr_ctx->num_processed++;
638
639         v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
640         v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
641
642         if (curr_ctx->num_processed == curr_ctx->translen
643             || curr_ctx->aborting) {
644                 dprintk(curr_ctx->dev, 2, "Finishing capture buffer fill\n");
645                 curr_ctx->num_processed = 0;
646                 v4l2_m2m_job_finish(vim2m_dev->m2m_dev, curr_ctx->fh.m2m_ctx);
647         } else {
648                 device_run(curr_ctx);
649         }
650 }
651
652 /*
653  * video ioctls
654  */
655 static int vidioc_querycap(struct file *file, void *priv,
656                            struct v4l2_capability *cap)
657 {
658         strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
659         strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
660         snprintf(cap->bus_info, sizeof(cap->bus_info),
661                  "platform:%s", MEM2MEM_NAME);
662         return 0;
663 }
664
665 static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
666 {
667         int i, num;
668         struct vim2m_fmt *fmt;
669
670         num = 0;
671
672         for (i = 0; i < NUM_FORMATS; ++i) {
673                 if (formats[i].types & type) {
674                         /* index-th format of type type found ? */
675                         if (num == f->index)
676                                 break;
677                         /*
678                          * Correct type but haven't reached our index yet,
679                          * just increment per-type index
680                          */
681                         ++num;
682                 }
683         }
684
685         if (i < NUM_FORMATS) {
686                 /* Format found */
687                 fmt = &formats[i];
688                 f->pixelformat = fmt->fourcc;
689                 return 0;
690         }
691
692         /* Format not found */
693         return -EINVAL;
694 }
695
696 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
697                                    struct v4l2_fmtdesc *f)
698 {
699         return enum_fmt(f, MEM2MEM_CAPTURE);
700 }
701
702 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
703                                    struct v4l2_fmtdesc *f)
704 {
705         return enum_fmt(f, MEM2MEM_OUTPUT);
706 }
707
708 static int vidioc_enum_framesizes(struct file *file, void *priv,
709                                   struct v4l2_frmsizeenum *fsize)
710 {
711         if (fsize->index != 0)
712                 return -EINVAL;
713
714         if (!find_format(fsize->pixel_format))
715                 return -EINVAL;
716
717         fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
718         fsize->stepwise.min_width = MIN_W;
719         fsize->stepwise.min_height = MIN_H;
720         fsize->stepwise.max_width = MAX_W;
721         fsize->stepwise.max_height = MAX_H;
722
723         get_alignment(fsize->pixel_format,
724                       &fsize->stepwise.step_width,
725                       &fsize->stepwise.step_height);
726         return 0;
727 }
728
729 static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
730 {
731         struct vb2_queue *vq;
732         struct vim2m_q_data *q_data;
733
734         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
735         if (!vq)
736                 return -EINVAL;
737
738         q_data = get_q_data(ctx, f->type);
739         if (!q_data)
740                 return -EINVAL;
741
742         f->fmt.pix.width        = q_data->width;
743         f->fmt.pix.height       = q_data->height;
744         f->fmt.pix.field        = V4L2_FIELD_NONE;
745         f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
746         f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
747         f->fmt.pix.sizeimage    = q_data->sizeimage;
748         f->fmt.pix.colorspace   = ctx->colorspace;
749         f->fmt.pix.xfer_func    = ctx->xfer_func;
750         f->fmt.pix.ycbcr_enc    = ctx->ycbcr_enc;
751         f->fmt.pix.quantization = ctx->quant;
752
753         return 0;
754 }
755
756 static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
757                                 struct v4l2_format *f)
758 {
759         return vidioc_g_fmt(file2ctx(file), f);
760 }
761
762 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
763                                 struct v4l2_format *f)
764 {
765         return vidioc_g_fmt(file2ctx(file), f);
766 }
767
768 static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt)
769 {
770         int walign, halign;
771         /*
772          * V4L2 specification specifies the driver corrects the
773          * format struct if any of the dimensions is unsupported
774          */
775         if (f->fmt.pix.height < MIN_H)
776                 f->fmt.pix.height = MIN_H;
777         else if (f->fmt.pix.height > MAX_H)
778                 f->fmt.pix.height = MAX_H;
779
780         if (f->fmt.pix.width < MIN_W)
781                 f->fmt.pix.width = MIN_W;
782         else if (f->fmt.pix.width > MAX_W)
783                 f->fmt.pix.width = MAX_W;
784
785         get_alignment(f->fmt.pix.pixelformat, &walign, &halign);
786         f->fmt.pix.width &= ~(walign - 1);
787         f->fmt.pix.height &= ~(halign - 1);
788         f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
789         f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
790         f->fmt.pix.field = V4L2_FIELD_NONE;
791
792         return 0;
793 }
794
795 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
796                                   struct v4l2_format *f)
797 {
798         struct vim2m_fmt *fmt;
799         struct vim2m_ctx *ctx = file2ctx(file);
800
801         fmt = find_format(f->fmt.pix.pixelformat);
802         if (!fmt) {
803                 f->fmt.pix.pixelformat = formats[0].fourcc;
804                 fmt = find_format(f->fmt.pix.pixelformat);
805         }
806         if (!(fmt->types & MEM2MEM_CAPTURE)) {
807                 v4l2_err(&ctx->dev->v4l2_dev,
808                          "Fourcc format (0x%08x) invalid.\n",
809                          f->fmt.pix.pixelformat);
810                 return -EINVAL;
811         }
812         f->fmt.pix.colorspace = ctx->colorspace;
813         f->fmt.pix.xfer_func = ctx->xfer_func;
814         f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
815         f->fmt.pix.quantization = ctx->quant;
816
817         return vidioc_try_fmt(f, fmt);
818 }
819
820 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
821                                   struct v4l2_format *f)
822 {
823         struct vim2m_fmt *fmt;
824         struct vim2m_ctx *ctx = file2ctx(file);
825
826         fmt = find_format(f->fmt.pix.pixelformat);
827         if (!fmt) {
828                 f->fmt.pix.pixelformat = formats[0].fourcc;
829                 fmt = find_format(f->fmt.pix.pixelformat);
830         }
831         if (!(fmt->types & MEM2MEM_OUTPUT)) {
832                 v4l2_err(&ctx->dev->v4l2_dev,
833                          "Fourcc format (0x%08x) invalid.\n",
834                          f->fmt.pix.pixelformat);
835                 return -EINVAL;
836         }
837         if (!f->fmt.pix.colorspace)
838                 f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
839
840         return vidioc_try_fmt(f, fmt);
841 }
842
843 static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
844 {
845         struct vim2m_q_data *q_data;
846         struct vb2_queue *vq;
847
848         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
849         if (!vq)
850                 return -EINVAL;
851
852         q_data = get_q_data(ctx, f->type);
853         if (!q_data)
854                 return -EINVAL;
855
856         if (vb2_is_busy(vq)) {
857                 v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
858                 return -EBUSY;
859         }
860
861         q_data->fmt             = find_format(f->fmt.pix.pixelformat);
862         q_data->width           = f->fmt.pix.width;
863         q_data->height          = f->fmt.pix.height;
864         q_data->sizeimage       = q_data->width * q_data->height
865                                 * q_data->fmt->depth >> 3;
866
867         dprintk(ctx->dev, 1,
868                 "Format for type %s: %dx%d (%d bpp), fmt: %c%c%c%c\n",
869                 type_name(f->type), q_data->width, q_data->height,
870                 q_data->fmt->depth,
871                 (q_data->fmt->fourcc & 0xff),
872                 (q_data->fmt->fourcc >>  8) & 0xff,
873                 (q_data->fmt->fourcc >> 16) & 0xff,
874                 (q_data->fmt->fourcc >> 24) & 0xff);
875
876         return 0;
877 }
878
879 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
880                                 struct v4l2_format *f)
881 {
882         int ret;
883
884         ret = vidioc_try_fmt_vid_cap(file, priv, f);
885         if (ret)
886                 return ret;
887
888         return vidioc_s_fmt(file2ctx(file), f);
889 }
890
891 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
892                                 struct v4l2_format *f)
893 {
894         struct vim2m_ctx *ctx = file2ctx(file);
895         int ret;
896
897         ret = vidioc_try_fmt_vid_out(file, priv, f);
898         if (ret)
899                 return ret;
900
901         ret = vidioc_s_fmt(file2ctx(file), f);
902         if (!ret) {
903                 ctx->colorspace = f->fmt.pix.colorspace;
904                 ctx->xfer_func = f->fmt.pix.xfer_func;
905                 ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
906                 ctx->quant = f->fmt.pix.quantization;
907         }
908         return ret;
909 }
910
911 static int vim2m_s_ctrl(struct v4l2_ctrl *ctrl)
912 {
913         struct vim2m_ctx *ctx =
914                 container_of(ctrl->handler, struct vim2m_ctx, hdl);
915
916         switch (ctrl->id) {
917         case V4L2_CID_HFLIP:
918                 if (ctrl->val)
919                         ctx->mode |= MEM2MEM_HFLIP;
920                 else
921                         ctx->mode &= ~MEM2MEM_HFLIP;
922                 break;
923
924         case V4L2_CID_VFLIP:
925                 if (ctrl->val)
926                         ctx->mode |= MEM2MEM_VFLIP;
927                 else
928                         ctx->mode &= ~MEM2MEM_VFLIP;
929                 break;
930
931         case V4L2_CID_TRANS_TIME_MSEC:
932                 ctx->transtime = ctrl->val;
933                 if (ctx->transtime < 1)
934                         ctx->transtime = 1;
935                 break;
936
937         case V4L2_CID_TRANS_NUM_BUFS:
938                 ctx->translen = ctrl->val;
939                 break;
940
941         default:
942                 v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
943                 return -EINVAL;
944         }
945
946         return 0;
947 }
948
949 static const struct v4l2_ctrl_ops vim2m_ctrl_ops = {
950         .s_ctrl = vim2m_s_ctrl,
951 };
952
953 static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
954         .vidioc_querycap        = vidioc_querycap,
955
956         .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
957         .vidioc_enum_framesizes = vidioc_enum_framesizes,
958         .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
959         .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
960         .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
961
962         .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
963         .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
964         .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
965         .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
966
967         .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
968         .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
969         .vidioc_qbuf            = v4l2_m2m_ioctl_qbuf,
970         .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
971         .vidioc_prepare_buf     = v4l2_m2m_ioctl_prepare_buf,
972         .vidioc_create_bufs     = v4l2_m2m_ioctl_create_bufs,
973         .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
974
975         .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
976         .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
977
978         .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
979         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
980 };
981
982 /*
983  * Queue operations
984  */
985
986 static int vim2m_queue_setup(struct vb2_queue *vq,
987                              unsigned int *nbuffers,
988                              unsigned int *nplanes,
989                              unsigned int sizes[],
990                              struct device *alloc_devs[])
991 {
992         struct vim2m_ctx *ctx = vb2_get_drv_priv(vq);
993         struct vim2m_q_data *q_data;
994         unsigned int size, count = *nbuffers;
995
996         q_data = get_q_data(ctx, vq->type);
997         if (!q_data)
998                 return -EINVAL;
999
1000         size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
1001
1002         while (size * count > MEM2MEM_VID_MEM_LIMIT)
1003                 (count)--;
1004         *nbuffers = count;
1005
1006         if (*nplanes)
1007                 return sizes[0] < size ? -EINVAL : 0;
1008
1009         *nplanes = 1;
1010         sizes[0] = size;
1011
1012         dprintk(ctx->dev, 1, "%s: get %d buffer(s) of size %d each.\n",
1013                 type_name(vq->type), count, size);
1014
1015         return 0;
1016 }
1017
1018 static int vim2m_buf_out_validate(struct vb2_buffer *vb)
1019 {
1020         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1021         struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1022
1023         if (vbuf->field == V4L2_FIELD_ANY)
1024                 vbuf->field = V4L2_FIELD_NONE;
1025         if (vbuf->field != V4L2_FIELD_NONE) {
1026                 dprintk(ctx->dev, 1, "%s field isn't supported\n", __func__);
1027                 return -EINVAL;
1028         }
1029
1030         return 0;
1031 }
1032
1033 static int vim2m_buf_prepare(struct vb2_buffer *vb)
1034 {
1035         struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1036         struct vim2m_q_data *q_data;
1037
1038         dprintk(ctx->dev, 2, "type: %s\n", type_name(vb->vb2_queue->type));
1039
1040         q_data = get_q_data(ctx, vb->vb2_queue->type);
1041         if (!q_data)
1042                 return -EINVAL;
1043         if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
1044                 dprintk(ctx->dev, 1,
1045                         "%s data will not fit into plane (%lu < %lu)\n",
1046                         __func__, vb2_plane_size(vb, 0),
1047                         (long)q_data->sizeimage);
1048                 return -EINVAL;
1049         }
1050
1051         vb2_set_plane_payload(vb, 0, q_data->sizeimage);
1052
1053         return 0;
1054 }
1055
1056 static void vim2m_buf_queue(struct vb2_buffer *vb)
1057 {
1058         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1059         struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1060
1061         v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1062 }
1063
1064 static int vim2m_start_streaming(struct vb2_queue *q, unsigned int count)
1065 {
1066         struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
1067         struct vim2m_q_data *q_data = get_q_data(ctx, q->type);
1068
1069         if (!q_data)
1070                 return -EINVAL;
1071
1072         if (V4L2_TYPE_IS_OUTPUT(q->type))
1073                 ctx->aborting = 0;
1074
1075         q_data->sequence = 0;
1076         return 0;
1077 }
1078
1079 static void vim2m_stop_streaming(struct vb2_queue *q)
1080 {
1081         struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
1082         struct vb2_v4l2_buffer *vbuf;
1083
1084         cancel_delayed_work_sync(&ctx->work_run);
1085
1086         for (;;) {
1087                 if (V4L2_TYPE_IS_OUTPUT(q->type))
1088                         vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1089                 else
1090                         vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1091                 if (!vbuf)
1092                         return;
1093                 v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
1094                                            &ctx->hdl);
1095                 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
1096         }
1097 }
1098
1099 static void vim2m_buf_request_complete(struct vb2_buffer *vb)
1100 {
1101         struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1102
1103         v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
1104 }
1105
1106 static const struct vb2_ops vim2m_qops = {
1107         .queue_setup     = vim2m_queue_setup,
1108         .buf_out_validate        = vim2m_buf_out_validate,
1109         .buf_prepare     = vim2m_buf_prepare,
1110         .buf_queue       = vim2m_buf_queue,
1111         .start_streaming = vim2m_start_streaming,
1112         .stop_streaming  = vim2m_stop_streaming,
1113         .wait_prepare    = vb2_ops_wait_prepare,
1114         .wait_finish     = vb2_ops_wait_finish,
1115         .buf_request_complete = vim2m_buf_request_complete,
1116 };
1117
1118 static int queue_init(void *priv, struct vb2_queue *src_vq,
1119                       struct vb2_queue *dst_vq)
1120 {
1121         struct vim2m_ctx *ctx = priv;
1122         int ret;
1123
1124         src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1125         src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1126         src_vq->drv_priv = ctx;
1127         src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1128         src_vq->ops = &vim2m_qops;
1129         src_vq->mem_ops = &vb2_vmalloc_memops;
1130         src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1131         src_vq->lock = &ctx->vb_mutex;
1132         src_vq->supports_requests = true;
1133
1134         ret = vb2_queue_init(src_vq);
1135         if (ret)
1136                 return ret;
1137
1138         dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1139         dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1140         dst_vq->drv_priv = ctx;
1141         dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1142         dst_vq->ops = &vim2m_qops;
1143         dst_vq->mem_ops = &vb2_vmalloc_memops;
1144         dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1145         dst_vq->lock = &ctx->vb_mutex;
1146
1147         return vb2_queue_init(dst_vq);
1148 }
1149
1150 static struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = {
1151         .ops = &vim2m_ctrl_ops,
1152         .id = V4L2_CID_TRANS_TIME_MSEC,
1153         .name = "Transaction Time (msec)",
1154         .type = V4L2_CTRL_TYPE_INTEGER,
1155         .min = 1,
1156         .max = 10001,
1157         .step = 1,
1158 };
1159
1160 static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs = {
1161         .ops = &vim2m_ctrl_ops,
1162         .id = V4L2_CID_TRANS_NUM_BUFS,
1163         .name = "Buffers Per Transaction",
1164         .type = V4L2_CTRL_TYPE_INTEGER,
1165         .def = 1,
1166         .min = 1,
1167         .max = MEM2MEM_DEF_NUM_BUFS,
1168         .step = 1,
1169 };
1170
1171 /*
1172  * File operations
1173  */
1174 static int vim2m_open(struct file *file)
1175 {
1176         struct vim2m_dev *dev = video_drvdata(file);
1177         struct vim2m_ctx *ctx = NULL;
1178         struct v4l2_ctrl_handler *hdl;
1179         int rc = 0;
1180
1181         if (mutex_lock_interruptible(&dev->dev_mutex))
1182                 return -ERESTARTSYS;
1183         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1184         if (!ctx) {
1185                 rc = -ENOMEM;
1186                 goto open_unlock;
1187         }
1188
1189         v4l2_fh_init(&ctx->fh, video_devdata(file));
1190         file->private_data = &ctx->fh;
1191         ctx->dev = dev;
1192         hdl = &ctx->hdl;
1193         v4l2_ctrl_handler_init(hdl, 4);
1194         v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
1195         v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
1196
1197         vim2m_ctrl_trans_time_msec.def = default_transtime;
1198         v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
1199         v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL);
1200         if (hdl->error) {
1201                 rc = hdl->error;
1202                 v4l2_ctrl_handler_free(hdl);
1203                 kfree(ctx);
1204                 goto open_unlock;
1205         }
1206         ctx->fh.ctrl_handler = hdl;
1207         v4l2_ctrl_handler_setup(hdl);
1208
1209         ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
1210         ctx->q_data[V4L2_M2M_SRC].width = 640;
1211         ctx->q_data[V4L2_M2M_SRC].height = 480;
1212         ctx->q_data[V4L2_M2M_SRC].sizeimage =
1213                 ctx->q_data[V4L2_M2M_SRC].width *
1214                 ctx->q_data[V4L2_M2M_SRC].height *
1215                 (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3);
1216         ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1217         ctx->colorspace = V4L2_COLORSPACE_REC709;
1218
1219         ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
1220
1221         mutex_init(&ctx->vb_mutex);
1222         INIT_DELAYED_WORK(&ctx->work_run, device_work);
1223
1224         if (IS_ERR(ctx->fh.m2m_ctx)) {
1225                 rc = PTR_ERR(ctx->fh.m2m_ctx);
1226
1227                 v4l2_ctrl_handler_free(hdl);
1228                 v4l2_fh_exit(&ctx->fh);
1229                 kfree(ctx);
1230                 goto open_unlock;
1231         }
1232
1233         v4l2_fh_add(&ctx->fh);
1234         atomic_inc(&dev->num_inst);
1235
1236         dprintk(dev, 1, "Created instance: %p, m2m_ctx: %p\n",
1237                 ctx, ctx->fh.m2m_ctx);
1238
1239 open_unlock:
1240         mutex_unlock(&dev->dev_mutex);
1241         return rc;
1242 }
1243
1244 static int vim2m_release(struct file *file)
1245 {
1246         struct vim2m_dev *dev = video_drvdata(file);
1247         struct vim2m_ctx *ctx = file2ctx(file);
1248
1249         dprintk(dev, 1, "Releasing instance %p\n", ctx);
1250
1251         v4l2_fh_del(&ctx->fh);
1252         v4l2_fh_exit(&ctx->fh);
1253         v4l2_ctrl_handler_free(&ctx->hdl);
1254         mutex_lock(&dev->dev_mutex);
1255         v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1256         mutex_unlock(&dev->dev_mutex);
1257         kfree(ctx);
1258
1259         atomic_dec(&dev->num_inst);
1260
1261         return 0;
1262 }
1263
1264 static void vim2m_device_release(struct video_device *vdev)
1265 {
1266         struct vim2m_dev *dev = container_of(vdev, struct vim2m_dev, vfd);
1267
1268         v4l2_device_unregister(&dev->v4l2_dev);
1269         v4l2_m2m_release(dev->m2m_dev);
1270 #ifdef CONFIG_MEDIA_CONTROLLER
1271         media_device_cleanup(&dev->mdev);
1272 #endif
1273         kfree(dev);
1274 }
1275
1276 static const struct v4l2_file_operations vim2m_fops = {
1277         .owner          = THIS_MODULE,
1278         .open           = vim2m_open,
1279         .release        = vim2m_release,
1280         .poll           = v4l2_m2m_fop_poll,
1281         .unlocked_ioctl = video_ioctl2,
1282         .mmap           = v4l2_m2m_fop_mmap,
1283 };
1284
1285 static const struct video_device vim2m_videodev = {
1286         .name           = MEM2MEM_NAME,
1287         .vfl_dir        = VFL_DIR_M2M,
1288         .fops           = &vim2m_fops,
1289         .ioctl_ops      = &vim2m_ioctl_ops,
1290         .minor          = -1,
1291         .release        = vim2m_device_release,
1292         .device_caps    = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
1293 };
1294
1295 static const struct v4l2_m2m_ops m2m_ops = {
1296         .device_run     = device_run,
1297         .job_ready      = job_ready,
1298         .job_abort      = job_abort,
1299 };
1300
1301 static const struct media_device_ops m2m_media_ops = {
1302         .req_validate = vb2_request_validate,
1303         .req_queue = v4l2_m2m_request_queue,
1304 };
1305
1306 static int vim2m_probe(struct platform_device *pdev)
1307 {
1308         struct vim2m_dev *dev;
1309         struct video_device *vfd;
1310         int ret;
1311
1312         dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1313         if (!dev)
1314                 return -ENOMEM;
1315
1316         ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1317         if (ret)
1318                 goto error_free;
1319
1320         atomic_set(&dev->num_inst, 0);
1321         mutex_init(&dev->dev_mutex);
1322
1323         dev->vfd = vim2m_videodev;
1324         vfd = &dev->vfd;
1325         vfd->lock = &dev->dev_mutex;
1326         vfd->v4l2_dev = &dev->v4l2_dev;
1327
1328         video_set_drvdata(vfd, dev);
1329         v4l2_info(&dev->v4l2_dev,
1330                   "Device registered as /dev/video%d\n", vfd->num);
1331
1332         platform_set_drvdata(pdev, dev);
1333
1334         dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
1335         if (IS_ERR(dev->m2m_dev)) {
1336                 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
1337                 ret = PTR_ERR(dev->m2m_dev);
1338                 dev->m2m_dev = NULL;
1339                 goto error_dev;
1340         }
1341
1342 #ifdef CONFIG_MEDIA_CONTROLLER
1343         dev->mdev.dev = &pdev->dev;
1344         strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model));
1345         strscpy(dev->mdev.bus_info, "platform:vim2m",
1346                 sizeof(dev->mdev.bus_info));
1347         media_device_init(&dev->mdev);
1348         dev->mdev.ops = &m2m_media_ops;
1349         dev->v4l2_dev.mdev = &dev->mdev;
1350 #endif
1351
1352         ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
1353         if (ret) {
1354                 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1355                 goto error_m2m;
1356         }
1357
1358 #ifdef CONFIG_MEDIA_CONTROLLER
1359         ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
1360                                                  MEDIA_ENT_F_PROC_VIDEO_SCALER);
1361         if (ret) {
1362                 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1363                 goto error_v4l2;
1364         }
1365
1366         ret = media_device_register(&dev->mdev);
1367         if (ret) {
1368                 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1369                 goto error_m2m_mc;
1370         }
1371 #endif
1372         return 0;
1373
1374 #ifdef CONFIG_MEDIA_CONTROLLER
1375 error_m2m_mc:
1376         v4l2_m2m_unregister_media_controller(dev->m2m_dev);
1377 #endif
1378 error_v4l2:
1379         video_unregister_device(&dev->vfd);
1380         /* vim2m_device_release called by video_unregister_device to release various objects */
1381         return ret;
1382 error_m2m:
1383         v4l2_m2m_release(dev->m2m_dev);
1384 error_dev:
1385         v4l2_device_unregister(&dev->v4l2_dev);
1386 error_free:
1387         kfree(dev);
1388
1389         return ret;
1390 }
1391
1392 static int vim2m_remove(struct platform_device *pdev)
1393 {
1394         struct vim2m_dev *dev = platform_get_drvdata(pdev);
1395
1396         v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
1397
1398 #ifdef CONFIG_MEDIA_CONTROLLER
1399         media_device_unregister(&dev->mdev);
1400         v4l2_m2m_unregister_media_controller(dev->m2m_dev);
1401 #endif
1402         video_unregister_device(&dev->vfd);
1403
1404         return 0;
1405 }
1406
1407 static struct platform_driver vim2m_pdrv = {
1408         .probe          = vim2m_probe,
1409         .remove         = vim2m_remove,
1410         .driver         = {
1411                 .name   = MEM2MEM_NAME,
1412         },
1413 };
1414
1415 static void __exit vim2m_exit(void)
1416 {
1417         platform_driver_unregister(&vim2m_pdrv);
1418         platform_device_unregister(&vim2m_pdev);
1419 }
1420
1421 static int __init vim2m_init(void)
1422 {
1423         int ret;
1424
1425         ret = platform_device_register(&vim2m_pdev);
1426         if (ret)
1427                 return ret;
1428
1429         ret = platform_driver_register(&vim2m_pdrv);
1430         if (ret)
1431                 platform_device_unregister(&vim2m_pdev);
1432
1433         return ret;
1434 }
1435
1436 module_init(vim2m_init);
1437 module_exit(vim2m_exit);