Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * A virtual v4l2-mem2mem example device.
0004  *
0005  * This is a virtual device driver for testing mem-to-mem videobuf framework.
0006  * It simulates a device that uses memory buffers for both source and
0007  * destination, processes the data and issues an "irq" (simulated by a delayed
0008  * workqueue).
0009  * The device is capable of multi-instance, multi-buffer-per-transaction
0010  * operation (via the mem2mem framework).
0011  *
0012  * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
0013  * Pawel Osciak, <pawel@osciak.com>
0014  * Marek Szyprowski, <m.szyprowski@samsung.com>
0015  */
0016 #include <linux/module.h>
0017 #include <linux/delay.h>
0018 #include <linux/fs.h>
0019 #include <linux/sched.h>
0020 #include <linux/slab.h>
0021 
0022 #include <linux/platform_device.h>
0023 #include <media/v4l2-mem2mem.h>
0024 #include <media/v4l2-device.h>
0025 #include <media/v4l2-ioctl.h>
0026 #include <media/v4l2-ctrls.h>
0027 #include <media/v4l2-event.h>
0028 #include <media/videobuf2-vmalloc.h>
0029 
0030 MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
0031 MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
0032 MODULE_LICENSE("GPL");
0033 MODULE_VERSION("0.2");
0034 MODULE_ALIAS("mem2mem_testdev");
0035 
0036 static unsigned int debug;
0037 module_param(debug, uint, 0644);
0038 MODULE_PARM_DESC(debug, "debug level");
0039 
0040 /* Default transaction time in msec */
0041 static unsigned int default_transtime = 40; /* Max 25 fps */
0042 module_param(default_transtime, uint, 0644);
0043 MODULE_PARM_DESC(default_transtime, "default transaction time in ms");
0044 
0045 #define MIN_W 32
0046 #define MIN_H 32
0047 #define MAX_W 640
0048 #define MAX_H 480
0049 
0050 /* Pixel alignment for non-bayer formats */
0051 #define WIDTH_ALIGN 2
0052 #define HEIGHT_ALIGN 1
0053 
0054 /* Pixel alignment for bayer formats */
0055 #define BAYER_WIDTH_ALIGN  2
0056 #define BAYER_HEIGHT_ALIGN 2
0057 
0058 /* Flags that indicate a format can be used for capture/output */
0059 #define MEM2MEM_CAPTURE BIT(0)
0060 #define MEM2MEM_OUTPUT  BIT(1)
0061 
0062 #define MEM2MEM_NAME        "vim2m"
0063 
0064 /* Per queue */
0065 #define MEM2MEM_DEF_NUM_BUFS    VIDEO_MAX_FRAME
0066 /* In bytes, per queue */
0067 #define MEM2MEM_VID_MEM_LIMIT   (16 * 1024 * 1024)
0068 
0069 /* Flags that indicate processing mode */
0070 #define MEM2MEM_HFLIP   BIT(0)
0071 #define MEM2MEM_VFLIP   BIT(1)
0072 
0073 #define dprintk(dev, lvl, fmt, arg...) \
0074     v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg)
0075 
0076 static void vim2m_dev_release(struct device *dev)
0077 {}
0078 
0079 static struct platform_device vim2m_pdev = {
0080     .name       = MEM2MEM_NAME,
0081     .dev.release    = vim2m_dev_release,
0082 };
0083 
0084 struct vim2m_fmt {
0085     u32 fourcc;
0086     int depth;
0087     /* Types the format can be used for */
0088     u32     types;
0089 };
0090 
0091 static struct vim2m_fmt formats[] = {
0092     {
0093         .fourcc = V4L2_PIX_FMT_RGB565,  /* rrrrrggg gggbbbbb */
0094         .depth  = 16,
0095         .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
0096     }, {
0097         .fourcc = V4L2_PIX_FMT_RGB565X, /* gggbbbbb rrrrrggg */
0098         .depth  = 16,
0099         .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
0100     }, {
0101         .fourcc = V4L2_PIX_FMT_RGB24,
0102         .depth  = 24,
0103         .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
0104     }, {
0105         .fourcc = V4L2_PIX_FMT_BGR24,
0106         .depth  = 24,
0107         .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
0108     }, {
0109         .fourcc = V4L2_PIX_FMT_YUYV,
0110         .depth  = 16,
0111         .types  = MEM2MEM_CAPTURE,
0112     }, {
0113         .fourcc = V4L2_PIX_FMT_SBGGR8,
0114         .depth  = 8,
0115         .types  = MEM2MEM_CAPTURE,
0116     }, {
0117         .fourcc = V4L2_PIX_FMT_SGBRG8,
0118         .depth  = 8,
0119         .types  = MEM2MEM_CAPTURE,
0120     }, {
0121         .fourcc = V4L2_PIX_FMT_SGRBG8,
0122         .depth  = 8,
0123         .types  = MEM2MEM_CAPTURE,
0124     }, {
0125         .fourcc = V4L2_PIX_FMT_SRGGB8,
0126         .depth  = 8,
0127         .types  = MEM2MEM_CAPTURE,
0128     },
0129 };
0130 
0131 #define NUM_FORMATS ARRAY_SIZE(formats)
0132 
0133 /* Per-queue, driver-specific private data */
0134 struct vim2m_q_data {
0135     unsigned int        width;
0136     unsigned int        height;
0137     unsigned int        sizeimage;
0138     unsigned int        sequence;
0139     struct vim2m_fmt    *fmt;
0140 };
0141 
0142 enum {
0143     V4L2_M2M_SRC = 0,
0144     V4L2_M2M_DST = 1,
0145 };
0146 
0147 #define V4L2_CID_TRANS_TIME_MSEC    (V4L2_CID_USER_BASE + 0x1000)
0148 #define V4L2_CID_TRANS_NUM_BUFS     (V4L2_CID_USER_BASE + 0x1001)
0149 
0150 static struct vim2m_fmt *find_format(u32 fourcc)
0151 {
0152     struct vim2m_fmt *fmt;
0153     unsigned int k;
0154 
0155     for (k = 0; k < NUM_FORMATS; k++) {
0156         fmt = &formats[k];
0157         if (fmt->fourcc == fourcc)
0158             break;
0159     }
0160 
0161     if (k == NUM_FORMATS)
0162         return NULL;
0163 
0164     return &formats[k];
0165 }
0166 
0167 static void get_alignment(u32 fourcc,
0168               unsigned int *walign, unsigned int *halign)
0169 {
0170     switch (fourcc) {
0171     case V4L2_PIX_FMT_SBGGR8:
0172     case V4L2_PIX_FMT_SGBRG8:
0173     case V4L2_PIX_FMT_SGRBG8:
0174     case V4L2_PIX_FMT_SRGGB8:
0175         *walign = BAYER_WIDTH_ALIGN;
0176         *halign = BAYER_HEIGHT_ALIGN;
0177         return;
0178     default:
0179         *walign = WIDTH_ALIGN;
0180         *halign = HEIGHT_ALIGN;
0181         return;
0182     }
0183 }
0184 
0185 struct vim2m_dev {
0186     struct v4l2_device  v4l2_dev;
0187     struct video_device vfd;
0188 #ifdef CONFIG_MEDIA_CONTROLLER
0189     struct media_device mdev;
0190 #endif
0191 
0192     atomic_t        num_inst;
0193     struct mutex        dev_mutex;
0194 
0195     struct v4l2_m2m_dev *m2m_dev;
0196 };
0197 
0198 struct vim2m_ctx {
0199     struct v4l2_fh      fh;
0200     struct vim2m_dev    *dev;
0201 
0202     struct v4l2_ctrl_handler hdl;
0203 
0204     /* Processed buffers in this transaction */
0205     u8          num_processed;
0206 
0207     /* Transaction length (i.e. how many buffers per transaction) */
0208     u32         translen;
0209     /* Transaction time (i.e. simulated processing time) in milliseconds */
0210     u32         transtime;
0211 
0212     struct mutex        vb_mutex;
0213     struct delayed_work work_run;
0214 
0215     /* Abort requested by m2m */
0216     int         aborting;
0217 
0218     /* Processing mode */
0219     int         mode;
0220 
0221     enum v4l2_colorspace    colorspace;
0222     enum v4l2_ycbcr_encoding ycbcr_enc;
0223     enum v4l2_xfer_func xfer_func;
0224     enum v4l2_quantization  quant;
0225 
0226     /* Source and destination queue data */
0227     struct vim2m_q_data   q_data[2];
0228 };
0229 
0230 static inline struct vim2m_ctx *file2ctx(struct file *file)
0231 {
0232     return container_of(file->private_data, struct vim2m_ctx, fh);
0233 }
0234 
0235 static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx,
0236                        enum v4l2_buf_type type)
0237 {
0238     switch (type) {
0239     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
0240         return &ctx->q_data[V4L2_M2M_SRC];
0241     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
0242         return &ctx->q_data[V4L2_M2M_DST];
0243     default:
0244         return NULL;
0245     }
0246 }
0247 
0248 static const char *type_name(enum v4l2_buf_type type)
0249 {
0250     switch (type) {
0251     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
0252         return "Output";
0253     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
0254         return "Capture";
0255     default:
0256         return "Invalid";
0257     }
0258 }
0259 
0260 #define CLIP(__color) \
0261     (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color)))
0262 
0263 static void copy_line(struct vim2m_q_data *q_data_out,
0264               u8 *src, u8 *dst, bool reverse)
0265 {
0266     int x, depth = q_data_out->fmt->depth >> 3;
0267 
0268     if (!reverse) {
0269         memcpy(dst, src, q_data_out->width * depth);
0270     } else {
0271         for (x = 0; x < q_data_out->width >> 1; x++) {
0272             memcpy(dst, src, depth);
0273             memcpy(dst + depth, src - depth, depth);
0274             src -= depth << 1;
0275             dst += depth << 1;
0276         }
0277         return;
0278     }
0279 }
0280 
0281 static void copy_two_pixels(struct vim2m_q_data *q_data_in,
0282                 struct vim2m_q_data *q_data_out,
0283                 u8 *src[2], u8 **dst, int ypos, bool reverse)
0284 {
0285     struct vim2m_fmt *out = q_data_out->fmt;
0286     struct vim2m_fmt *in = q_data_in->fmt;
0287     u8 _r[2], _g[2], _b[2], *r, *g, *b;
0288     int i;
0289 
0290     /* Step 1: read two consecutive pixels from src pointer */
0291 
0292     r = _r;
0293     g = _g;
0294     b = _b;
0295 
0296     switch (in->fourcc) {
0297     case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
0298         for (i = 0; i < 2; i++) {
0299             u16 pix = le16_to_cpu(*(__le16 *)(src[i]));
0300 
0301             *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07;
0302             *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03;
0303             *b++ = (u8)((pix & 0x1f) << 3) | 0x07;
0304         }
0305         break;
0306     case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
0307         for (i = 0; i < 2; i++) {
0308             u16 pix = be16_to_cpu(*(__be16 *)(src[i]));
0309 
0310             *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07;
0311             *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03;
0312             *b++ = (u8)((pix & 0x1f) << 3) | 0x07;
0313         }
0314         break;
0315     default:
0316     case V4L2_PIX_FMT_RGB24:
0317         for (i = 0; i < 2; i++) {
0318             *r++ = src[i][0];
0319             *g++ = src[i][1];
0320             *b++ = src[i][2];
0321         }
0322         break;
0323     case V4L2_PIX_FMT_BGR24:
0324         for (i = 0; i < 2; i++) {
0325             *b++ = src[i][0];
0326             *g++ = src[i][1];
0327             *r++ = src[i][2];
0328         }
0329         break;
0330     }
0331 
0332     /* Step 2: store two consecutive points, reversing them if needed */
0333 
0334     r = _r;
0335     g = _g;
0336     b = _b;
0337 
0338     switch (out->fourcc) {
0339     case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
0340         for (i = 0; i < 2; i++) {
0341             u16 pix;
0342             __le16 *dst_pix = (__le16 *)*dst;
0343 
0344             pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) |
0345                   (*b >> 3);
0346 
0347             *dst_pix = cpu_to_le16(pix);
0348 
0349             *dst += 2;
0350         }
0351         return;
0352     case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
0353         for (i = 0; i < 2; i++) {
0354             u16 pix;
0355             __be16 *dst_pix = (__be16 *)*dst;
0356 
0357             pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) |
0358                   (*b >> 3);
0359 
0360             *dst_pix = cpu_to_be16(pix);
0361 
0362             *dst += 2;
0363         }
0364         return;
0365     case V4L2_PIX_FMT_RGB24:
0366         for (i = 0; i < 2; i++) {
0367             *(*dst)++ = *r++;
0368             *(*dst)++ = *g++;
0369             *(*dst)++ = *b++;
0370         }
0371         return;
0372     case V4L2_PIX_FMT_BGR24:
0373         for (i = 0; i < 2; i++) {
0374             *(*dst)++ = *b++;
0375             *(*dst)++ = *g++;
0376             *(*dst)++ = *r++;
0377         }
0378         return;
0379     case V4L2_PIX_FMT_YUYV:
0380     default:
0381     {
0382         u8 y, y1, u, v;
0383 
0384         y = ((8453  * (*r) + 16594 * (*g) +  3223 * (*b)
0385              + 524288) >> 15);
0386         u = ((-4878 * (*r) - 9578  * (*g) + 14456 * (*b)
0387              + 4210688) >> 15);
0388         v = ((14456 * (*r++) - 12105 * (*g++) - 2351 * (*b++)
0389              + 4210688) >> 15);
0390         y1 = ((8453 * (*r) + 16594 * (*g) +  3223 * (*b)
0391              + 524288) >> 15);
0392 
0393         *(*dst)++ = y;
0394         *(*dst)++ = u;
0395 
0396         *(*dst)++ = y1;
0397         *(*dst)++ = v;
0398         return;
0399     }
0400     case V4L2_PIX_FMT_SBGGR8:
0401         if (!(ypos & 1)) {
0402             *(*dst)++ = *b;
0403             *(*dst)++ = *++g;
0404         } else {
0405             *(*dst)++ = *g;
0406             *(*dst)++ = *++r;
0407         }
0408         return;
0409     case V4L2_PIX_FMT_SGBRG8:
0410         if (!(ypos & 1)) {
0411             *(*dst)++ = *g;
0412             *(*dst)++ = *++b;
0413         } else {
0414             *(*dst)++ = *r;
0415             *(*dst)++ = *++g;
0416         }
0417         return;
0418     case V4L2_PIX_FMT_SGRBG8:
0419         if (!(ypos & 1)) {
0420             *(*dst)++ = *g;
0421             *(*dst)++ = *++r;
0422         } else {
0423             *(*dst)++ = *b;
0424             *(*dst)++ = *++g;
0425         }
0426         return;
0427     case V4L2_PIX_FMT_SRGGB8:
0428         if (!(ypos & 1)) {
0429             *(*dst)++ = *r;
0430             *(*dst)++ = *++g;
0431         } else {
0432             *(*dst)++ = *g;
0433             *(*dst)++ = *++b;
0434         }
0435         return;
0436     }
0437 }
0438 
0439 static int device_process(struct vim2m_ctx *ctx,
0440               struct vb2_v4l2_buffer *in_vb,
0441               struct vb2_v4l2_buffer *out_vb)
0442 {
0443     struct vim2m_dev *dev = ctx->dev;
0444     struct vim2m_q_data *q_data_in, *q_data_out;
0445     u8 *p_in, *p_line, *p_in_x[2], *p, *p_out;
0446     unsigned int width, height, bytesperline, bytes_per_pixel;
0447     unsigned int x, y, y_in, y_out, x_int, x_fract, x_err, x_offset;
0448     int start, end, step;
0449 
0450     q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
0451     if (!q_data_in)
0452         return 0;
0453     bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3;
0454     bytes_per_pixel = q_data_in->fmt->depth >> 3;
0455 
0456     q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
0457     if (!q_data_out)
0458         return 0;
0459 
0460     /* As we're doing scaling, use the output dimensions here */
0461     height = q_data_out->height;
0462     width = q_data_out->width;
0463 
0464     p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
0465     p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
0466     if (!p_in || !p_out) {
0467         v4l2_err(&dev->v4l2_dev,
0468              "Acquiring kernel pointers to buffers failed\n");
0469         return -EFAULT;
0470     }
0471 
0472     out_vb->sequence = q_data_out->sequence++;
0473     in_vb->sequence = q_data_in->sequence++;
0474     v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true);
0475 
0476     if (ctx->mode & MEM2MEM_VFLIP) {
0477         start = height - 1;
0478         end = -1;
0479         step = -1;
0480     } else {
0481         start = 0;
0482         end = height;
0483         step = 1;
0484     }
0485     y_out = 0;
0486 
0487     /*
0488      * When format and resolution are identical,
0489      * we can use a faster copy logic
0490      */
0491     if (q_data_in->fmt->fourcc == q_data_out->fmt->fourcc &&
0492         q_data_in->width == q_data_out->width &&
0493         q_data_in->height == q_data_out->height) {
0494         for (y = start; y != end; y += step, y_out++) {
0495             p = p_in + (y * bytesperline);
0496             if (ctx->mode & MEM2MEM_HFLIP)
0497                 p += bytesperline - (q_data_in->fmt->depth >> 3);
0498 
0499             copy_line(q_data_out, p, p_out,
0500                   ctx->mode & MEM2MEM_HFLIP);
0501 
0502             p_out += bytesperline;
0503         }
0504         return 0;
0505     }
0506 
0507     /* Slower algorithm with format conversion, hflip, vflip and scaler */
0508 
0509     /* To speed scaler up, use Bresenham for X dimension */
0510     x_int = q_data_in->width / q_data_out->width;
0511     x_fract = q_data_in->width % q_data_out->width;
0512 
0513     for (y = start; y != end; y += step, y_out++) {
0514         y_in = (y * q_data_in->height) / q_data_out->height;
0515         x_offset = 0;
0516         x_err = 0;
0517 
0518         p_line = p_in + (y_in * bytesperline);
0519         if (ctx->mode & MEM2MEM_HFLIP)
0520             p_line += bytesperline - (q_data_in->fmt->depth >> 3);
0521         p_in_x[0] = p_line;
0522 
0523         for (x = 0; x < width >> 1; x++) {
0524             x_offset += x_int;
0525             x_err += x_fract;
0526             if (x_err > width) {
0527                 x_offset++;
0528                 x_err -= width;
0529             }
0530 
0531             if (ctx->mode & MEM2MEM_HFLIP)
0532                 p_in_x[1] = p_line - x_offset * bytes_per_pixel;
0533             else
0534                 p_in_x[1] = p_line + x_offset * bytes_per_pixel;
0535 
0536             copy_two_pixels(q_data_in, q_data_out,
0537                     p_in_x, &p_out, y_out,
0538                     ctx->mode & MEM2MEM_HFLIP);
0539 
0540             /* Calculate the next p_in_x0 */
0541             x_offset += x_int;
0542             x_err += x_fract;
0543             if (x_err > width) {
0544                 x_offset++;
0545                 x_err -= width;
0546             }
0547 
0548             if (ctx->mode & MEM2MEM_HFLIP)
0549                 p_in_x[0] = p_line - x_offset * bytes_per_pixel;
0550             else
0551                 p_in_x[0] = p_line + x_offset * bytes_per_pixel;
0552         }
0553     }
0554 
0555     return 0;
0556 }
0557 
0558 /*
0559  * mem2mem callbacks
0560  */
0561 
0562 /*
0563  * job_ready() - check whether an instance is ready to be scheduled to run
0564  */
0565 static int job_ready(void *priv)
0566 {
0567     struct vim2m_ctx *ctx = priv;
0568 
0569     if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen
0570         || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) {
0571         dprintk(ctx->dev, 1, "Not enough buffers available\n");
0572         return 0;
0573     }
0574 
0575     return 1;
0576 }
0577 
0578 static void job_abort(void *priv)
0579 {
0580     struct vim2m_ctx *ctx = priv;
0581 
0582     /* Will cancel the transaction in the next interrupt handler */
0583     ctx->aborting = 1;
0584 }
0585 
0586 /* device_run() - prepares and starts the device
0587  *
0588  * This simulates all the immediate preparations required before starting
0589  * a device. This will be called by the framework when it decides to schedule
0590  * a particular instance.
0591  */
0592 static void device_run(void *priv)
0593 {
0594     struct vim2m_ctx *ctx = priv;
0595     struct vb2_v4l2_buffer *src_buf, *dst_buf;
0596 
0597     src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
0598     dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
0599 
0600     /* Apply request controls if any */
0601     v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
0602                 &ctx->hdl);
0603 
0604     device_process(ctx, src_buf, dst_buf);
0605 
0606     /* Complete request controls if any */
0607     v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
0608                    &ctx->hdl);
0609 
0610     /* Run delayed work, which simulates a hardware irq  */
0611     schedule_delayed_work(&ctx->work_run, msecs_to_jiffies(ctx->transtime));
0612 }
0613 
0614 static void device_work(struct work_struct *w)
0615 {
0616     struct vim2m_ctx *curr_ctx;
0617     struct vim2m_dev *vim2m_dev;
0618     struct vb2_v4l2_buffer *src_vb, *dst_vb;
0619 
0620     curr_ctx = container_of(w, struct vim2m_ctx, work_run.work);
0621 
0622     vim2m_dev = curr_ctx->dev;
0623 
0624     src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
0625     dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
0626 
0627     curr_ctx->num_processed++;
0628 
0629     v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
0630     v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
0631 
0632     if (curr_ctx->num_processed == curr_ctx->translen
0633         || curr_ctx->aborting) {
0634         dprintk(curr_ctx->dev, 2, "Finishing capture buffer fill\n");
0635         curr_ctx->num_processed = 0;
0636         v4l2_m2m_job_finish(vim2m_dev->m2m_dev, curr_ctx->fh.m2m_ctx);
0637     } else {
0638         device_run(curr_ctx);
0639     }
0640 }
0641 
0642 /*
0643  * video ioctls
0644  */
0645 static int vidioc_querycap(struct file *file, void *priv,
0646                struct v4l2_capability *cap)
0647 {
0648     strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
0649     strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
0650     snprintf(cap->bus_info, sizeof(cap->bus_info),
0651          "platform:%s", MEM2MEM_NAME);
0652     return 0;
0653 }
0654 
0655 static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
0656 {
0657     int i, num;
0658     struct vim2m_fmt *fmt;
0659 
0660     num = 0;
0661 
0662     for (i = 0; i < NUM_FORMATS; ++i) {
0663         if (formats[i].types & type) {
0664             /* index-th format of type type found ? */
0665             if (num == f->index)
0666                 break;
0667             /*
0668              * Correct type but haven't reached our index yet,
0669              * just increment per-type index
0670              */
0671             ++num;
0672         }
0673     }
0674 
0675     if (i < NUM_FORMATS) {
0676         /* Format found */
0677         fmt = &formats[i];
0678         f->pixelformat = fmt->fourcc;
0679         return 0;
0680     }
0681 
0682     /* Format not found */
0683     return -EINVAL;
0684 }
0685 
0686 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
0687                    struct v4l2_fmtdesc *f)
0688 {
0689     return enum_fmt(f, MEM2MEM_CAPTURE);
0690 }
0691 
0692 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
0693                    struct v4l2_fmtdesc *f)
0694 {
0695     return enum_fmt(f, MEM2MEM_OUTPUT);
0696 }
0697 
0698 static int vidioc_enum_framesizes(struct file *file, void *priv,
0699                   struct v4l2_frmsizeenum *fsize)
0700 {
0701     if (fsize->index != 0)
0702         return -EINVAL;
0703 
0704     if (!find_format(fsize->pixel_format))
0705         return -EINVAL;
0706 
0707     fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
0708     fsize->stepwise.min_width = MIN_W;
0709     fsize->stepwise.min_height = MIN_H;
0710     fsize->stepwise.max_width = MAX_W;
0711     fsize->stepwise.max_height = MAX_H;
0712 
0713     get_alignment(fsize->pixel_format,
0714               &fsize->stepwise.step_width,
0715               &fsize->stepwise.step_height);
0716     return 0;
0717 }
0718 
0719 static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
0720 {
0721     struct vb2_queue *vq;
0722     struct vim2m_q_data *q_data;
0723 
0724     vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
0725     if (!vq)
0726         return -EINVAL;
0727 
0728     q_data = get_q_data(ctx, f->type);
0729     if (!q_data)
0730         return -EINVAL;
0731 
0732     f->fmt.pix.width    = q_data->width;
0733     f->fmt.pix.height   = q_data->height;
0734     f->fmt.pix.field    = V4L2_FIELD_NONE;
0735     f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
0736     f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
0737     f->fmt.pix.sizeimage    = q_data->sizeimage;
0738     f->fmt.pix.colorspace   = ctx->colorspace;
0739     f->fmt.pix.xfer_func    = ctx->xfer_func;
0740     f->fmt.pix.ycbcr_enc    = ctx->ycbcr_enc;
0741     f->fmt.pix.quantization = ctx->quant;
0742 
0743     return 0;
0744 }
0745 
0746 static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
0747                 struct v4l2_format *f)
0748 {
0749     return vidioc_g_fmt(file2ctx(file), f);
0750 }
0751 
0752 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
0753                 struct v4l2_format *f)
0754 {
0755     return vidioc_g_fmt(file2ctx(file), f);
0756 }
0757 
0758 static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt)
0759 {
0760     int walign, halign;
0761     /*
0762      * V4L2 specification specifies the driver corrects the
0763      * format struct if any of the dimensions is unsupported
0764      */
0765     if (f->fmt.pix.height < MIN_H)
0766         f->fmt.pix.height = MIN_H;
0767     else if (f->fmt.pix.height > MAX_H)
0768         f->fmt.pix.height = MAX_H;
0769 
0770     if (f->fmt.pix.width < MIN_W)
0771         f->fmt.pix.width = MIN_W;
0772     else if (f->fmt.pix.width > MAX_W)
0773         f->fmt.pix.width = MAX_W;
0774 
0775     get_alignment(f->fmt.pix.pixelformat, &walign, &halign);
0776     f->fmt.pix.width &= ~(walign - 1);
0777     f->fmt.pix.height &= ~(halign - 1);
0778     f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
0779     f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
0780     f->fmt.pix.field = V4L2_FIELD_NONE;
0781 
0782     return 0;
0783 }
0784 
0785 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
0786                   struct v4l2_format *f)
0787 {
0788     struct vim2m_fmt *fmt;
0789     struct vim2m_ctx *ctx = file2ctx(file);
0790 
0791     fmt = find_format(f->fmt.pix.pixelformat);
0792     if (!fmt) {
0793         f->fmt.pix.pixelformat = formats[0].fourcc;
0794         fmt = find_format(f->fmt.pix.pixelformat);
0795     }
0796     if (!(fmt->types & MEM2MEM_CAPTURE)) {
0797         v4l2_err(&ctx->dev->v4l2_dev,
0798              "Fourcc format (0x%08x) invalid.\n",
0799              f->fmt.pix.pixelformat);
0800         return -EINVAL;
0801     }
0802     f->fmt.pix.colorspace = ctx->colorspace;
0803     f->fmt.pix.xfer_func = ctx->xfer_func;
0804     f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
0805     f->fmt.pix.quantization = ctx->quant;
0806 
0807     return vidioc_try_fmt(f, fmt);
0808 }
0809 
0810 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
0811                   struct v4l2_format *f)
0812 {
0813     struct vim2m_fmt *fmt;
0814     struct vim2m_ctx *ctx = file2ctx(file);
0815 
0816     fmt = find_format(f->fmt.pix.pixelformat);
0817     if (!fmt) {
0818         f->fmt.pix.pixelformat = formats[0].fourcc;
0819         fmt = find_format(f->fmt.pix.pixelformat);
0820     }
0821     if (!(fmt->types & MEM2MEM_OUTPUT)) {
0822         v4l2_err(&ctx->dev->v4l2_dev,
0823              "Fourcc format (0x%08x) invalid.\n",
0824              f->fmt.pix.pixelformat);
0825         return -EINVAL;
0826     }
0827     if (!f->fmt.pix.colorspace)
0828         f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
0829 
0830     return vidioc_try_fmt(f, fmt);
0831 }
0832 
0833 static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
0834 {
0835     struct vim2m_q_data *q_data;
0836     struct vb2_queue *vq;
0837 
0838     vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
0839     if (!vq)
0840         return -EINVAL;
0841 
0842     q_data = get_q_data(ctx, f->type);
0843     if (!q_data)
0844         return -EINVAL;
0845 
0846     if (vb2_is_busy(vq)) {
0847         v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
0848         return -EBUSY;
0849     }
0850 
0851     q_data->fmt     = find_format(f->fmt.pix.pixelformat);
0852     q_data->width       = f->fmt.pix.width;
0853     q_data->height      = f->fmt.pix.height;
0854     q_data->sizeimage   = q_data->width * q_data->height
0855                 * q_data->fmt->depth >> 3;
0856 
0857     dprintk(ctx->dev, 1,
0858         "Format for type %s: %dx%d (%d bpp), fmt: %c%c%c%c\n",
0859         type_name(f->type), q_data->width, q_data->height,
0860         q_data->fmt->depth,
0861         (q_data->fmt->fourcc & 0xff),
0862         (q_data->fmt->fourcc >>  8) & 0xff,
0863         (q_data->fmt->fourcc >> 16) & 0xff,
0864         (q_data->fmt->fourcc >> 24) & 0xff);
0865 
0866     return 0;
0867 }
0868 
0869 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
0870                 struct v4l2_format *f)
0871 {
0872     int ret;
0873 
0874     ret = vidioc_try_fmt_vid_cap(file, priv, f);
0875     if (ret)
0876         return ret;
0877 
0878     return vidioc_s_fmt(file2ctx(file), f);
0879 }
0880 
0881 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
0882                 struct v4l2_format *f)
0883 {
0884     struct vim2m_ctx *ctx = file2ctx(file);
0885     int ret;
0886 
0887     ret = vidioc_try_fmt_vid_out(file, priv, f);
0888     if (ret)
0889         return ret;
0890 
0891     ret = vidioc_s_fmt(file2ctx(file), f);
0892     if (!ret) {
0893         ctx->colorspace = f->fmt.pix.colorspace;
0894         ctx->xfer_func = f->fmt.pix.xfer_func;
0895         ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
0896         ctx->quant = f->fmt.pix.quantization;
0897     }
0898     return ret;
0899 }
0900 
0901 static int vim2m_s_ctrl(struct v4l2_ctrl *ctrl)
0902 {
0903     struct vim2m_ctx *ctx =
0904         container_of(ctrl->handler, struct vim2m_ctx, hdl);
0905 
0906     switch (ctrl->id) {
0907     case V4L2_CID_HFLIP:
0908         if (ctrl->val)
0909             ctx->mode |= MEM2MEM_HFLIP;
0910         else
0911             ctx->mode &= ~MEM2MEM_HFLIP;
0912         break;
0913 
0914     case V4L2_CID_VFLIP:
0915         if (ctrl->val)
0916             ctx->mode |= MEM2MEM_VFLIP;
0917         else
0918             ctx->mode &= ~MEM2MEM_VFLIP;
0919         break;
0920 
0921     case V4L2_CID_TRANS_TIME_MSEC:
0922         ctx->transtime = ctrl->val;
0923         if (ctx->transtime < 1)
0924             ctx->transtime = 1;
0925         break;
0926 
0927     case V4L2_CID_TRANS_NUM_BUFS:
0928         ctx->translen = ctrl->val;
0929         break;
0930 
0931     default:
0932         v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
0933         return -EINVAL;
0934     }
0935 
0936     return 0;
0937 }
0938 
0939 static const struct v4l2_ctrl_ops vim2m_ctrl_ops = {
0940     .s_ctrl = vim2m_s_ctrl,
0941 };
0942 
0943 static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
0944     .vidioc_querycap    = vidioc_querycap,
0945 
0946     .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
0947     .vidioc_enum_framesizes = vidioc_enum_framesizes,
0948     .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
0949     .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
0950     .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
0951 
0952     .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
0953     .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
0954     .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
0955     .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
0956 
0957     .vidioc_reqbufs     = v4l2_m2m_ioctl_reqbufs,
0958     .vidioc_querybuf    = v4l2_m2m_ioctl_querybuf,
0959     .vidioc_qbuf        = v4l2_m2m_ioctl_qbuf,
0960     .vidioc_dqbuf       = v4l2_m2m_ioctl_dqbuf,
0961     .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
0962     .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
0963     .vidioc_expbuf      = v4l2_m2m_ioctl_expbuf,
0964 
0965     .vidioc_streamon    = v4l2_m2m_ioctl_streamon,
0966     .vidioc_streamoff   = v4l2_m2m_ioctl_streamoff,
0967 
0968     .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
0969     .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
0970 };
0971 
0972 /*
0973  * Queue operations
0974  */
0975 
0976 static int vim2m_queue_setup(struct vb2_queue *vq,
0977                  unsigned int *nbuffers,
0978                  unsigned int *nplanes,
0979                  unsigned int sizes[],
0980                  struct device *alloc_devs[])
0981 {
0982     struct vim2m_ctx *ctx = vb2_get_drv_priv(vq);
0983     struct vim2m_q_data *q_data;
0984     unsigned int size, count = *nbuffers;
0985 
0986     q_data = get_q_data(ctx, vq->type);
0987     if (!q_data)
0988         return -EINVAL;
0989 
0990     size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
0991 
0992     while (size * count > MEM2MEM_VID_MEM_LIMIT)
0993         (count)--;
0994     *nbuffers = count;
0995 
0996     if (*nplanes)
0997         return sizes[0] < size ? -EINVAL : 0;
0998 
0999     *nplanes = 1;
1000     sizes[0] = size;
1001 
1002     dprintk(ctx->dev, 1, "%s: get %d buffer(s) of size %d each.\n",
1003         type_name(vq->type), count, size);
1004 
1005     return 0;
1006 }
1007 
1008 static int vim2m_buf_out_validate(struct vb2_buffer *vb)
1009 {
1010     struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1011     struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1012 
1013     if (vbuf->field == V4L2_FIELD_ANY)
1014         vbuf->field = V4L2_FIELD_NONE;
1015     if (vbuf->field != V4L2_FIELD_NONE) {
1016         dprintk(ctx->dev, 1, "%s field isn't supported\n", __func__);
1017         return -EINVAL;
1018     }
1019 
1020     return 0;
1021 }
1022 
1023 static int vim2m_buf_prepare(struct vb2_buffer *vb)
1024 {
1025     struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1026     struct vim2m_q_data *q_data;
1027 
1028     dprintk(ctx->dev, 2, "type: %s\n", type_name(vb->vb2_queue->type));
1029 
1030     q_data = get_q_data(ctx, vb->vb2_queue->type);
1031     if (!q_data)
1032         return -EINVAL;
1033     if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
1034         dprintk(ctx->dev, 1,
1035             "%s data will not fit into plane (%lu < %lu)\n",
1036             __func__, vb2_plane_size(vb, 0),
1037             (long)q_data->sizeimage);
1038         return -EINVAL;
1039     }
1040 
1041     vb2_set_plane_payload(vb, 0, q_data->sizeimage);
1042 
1043     return 0;
1044 }
1045 
1046 static void vim2m_buf_queue(struct vb2_buffer *vb)
1047 {
1048     struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1049     struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1050 
1051     v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
1052 }
1053 
1054 static int vim2m_start_streaming(struct vb2_queue *q, unsigned int count)
1055 {
1056     struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
1057     struct vim2m_q_data *q_data = get_q_data(ctx, q->type);
1058 
1059     if (!q_data)
1060         return -EINVAL;
1061 
1062     if (V4L2_TYPE_IS_OUTPUT(q->type))
1063         ctx->aborting = 0;
1064 
1065     q_data->sequence = 0;
1066     return 0;
1067 }
1068 
1069 static void vim2m_stop_streaming(struct vb2_queue *q)
1070 {
1071     struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
1072     struct vb2_v4l2_buffer *vbuf;
1073 
1074     cancel_delayed_work_sync(&ctx->work_run);
1075 
1076     for (;;) {
1077         if (V4L2_TYPE_IS_OUTPUT(q->type))
1078             vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
1079         else
1080             vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
1081         if (!vbuf)
1082             return;
1083         v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
1084                        &ctx->hdl);
1085         v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
1086     }
1087 }
1088 
1089 static void vim2m_buf_request_complete(struct vb2_buffer *vb)
1090 {
1091     struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
1092 
1093     v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
1094 }
1095 
1096 static const struct vb2_ops vim2m_qops = {
1097     .queue_setup     = vim2m_queue_setup,
1098     .buf_out_validate    = vim2m_buf_out_validate,
1099     .buf_prepare     = vim2m_buf_prepare,
1100     .buf_queue   = vim2m_buf_queue,
1101     .start_streaming = vim2m_start_streaming,
1102     .stop_streaming  = vim2m_stop_streaming,
1103     .wait_prepare    = vb2_ops_wait_prepare,
1104     .wait_finish     = vb2_ops_wait_finish,
1105     .buf_request_complete = vim2m_buf_request_complete,
1106 };
1107 
1108 static int queue_init(void *priv, struct vb2_queue *src_vq,
1109               struct vb2_queue *dst_vq)
1110 {
1111     struct vim2m_ctx *ctx = priv;
1112     int ret;
1113 
1114     src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1115     src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1116     src_vq->drv_priv = ctx;
1117     src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1118     src_vq->ops = &vim2m_qops;
1119     src_vq->mem_ops = &vb2_vmalloc_memops;
1120     src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1121     src_vq->lock = &ctx->vb_mutex;
1122     src_vq->supports_requests = true;
1123 
1124     ret = vb2_queue_init(src_vq);
1125     if (ret)
1126         return ret;
1127 
1128     dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1129     dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
1130     dst_vq->drv_priv = ctx;
1131     dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
1132     dst_vq->ops = &vim2m_qops;
1133     dst_vq->mem_ops = &vb2_vmalloc_memops;
1134     dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
1135     dst_vq->lock = &ctx->vb_mutex;
1136 
1137     return vb2_queue_init(dst_vq);
1138 }
1139 
1140 static struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = {
1141     .ops = &vim2m_ctrl_ops,
1142     .id = V4L2_CID_TRANS_TIME_MSEC,
1143     .name = "Transaction Time (msec)",
1144     .type = V4L2_CTRL_TYPE_INTEGER,
1145     .min = 1,
1146     .max = 10001,
1147     .step = 1,
1148 };
1149 
1150 static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs = {
1151     .ops = &vim2m_ctrl_ops,
1152     .id = V4L2_CID_TRANS_NUM_BUFS,
1153     .name = "Buffers Per Transaction",
1154     .type = V4L2_CTRL_TYPE_INTEGER,
1155     .def = 1,
1156     .min = 1,
1157     .max = MEM2MEM_DEF_NUM_BUFS,
1158     .step = 1,
1159 };
1160 
1161 /*
1162  * File operations
1163  */
1164 static int vim2m_open(struct file *file)
1165 {
1166     struct vim2m_dev *dev = video_drvdata(file);
1167     struct vim2m_ctx *ctx = NULL;
1168     struct v4l2_ctrl_handler *hdl;
1169     int rc = 0;
1170 
1171     if (mutex_lock_interruptible(&dev->dev_mutex))
1172         return -ERESTARTSYS;
1173     ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1174     if (!ctx) {
1175         rc = -ENOMEM;
1176         goto open_unlock;
1177     }
1178 
1179     v4l2_fh_init(&ctx->fh, video_devdata(file));
1180     file->private_data = &ctx->fh;
1181     ctx->dev = dev;
1182     hdl = &ctx->hdl;
1183     v4l2_ctrl_handler_init(hdl, 4);
1184     v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
1185     v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
1186 
1187     vim2m_ctrl_trans_time_msec.def = default_transtime;
1188     v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
1189     v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL);
1190     if (hdl->error) {
1191         rc = hdl->error;
1192         v4l2_ctrl_handler_free(hdl);
1193         kfree(ctx);
1194         goto open_unlock;
1195     }
1196     ctx->fh.ctrl_handler = hdl;
1197     v4l2_ctrl_handler_setup(hdl);
1198 
1199     ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
1200     ctx->q_data[V4L2_M2M_SRC].width = 640;
1201     ctx->q_data[V4L2_M2M_SRC].height = 480;
1202     ctx->q_data[V4L2_M2M_SRC].sizeimage =
1203         ctx->q_data[V4L2_M2M_SRC].width *
1204         ctx->q_data[V4L2_M2M_SRC].height *
1205         (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3);
1206     ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1207     ctx->colorspace = V4L2_COLORSPACE_REC709;
1208 
1209     ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
1210 
1211     mutex_init(&ctx->vb_mutex);
1212     INIT_DELAYED_WORK(&ctx->work_run, device_work);
1213 
1214     if (IS_ERR(ctx->fh.m2m_ctx)) {
1215         rc = PTR_ERR(ctx->fh.m2m_ctx);
1216 
1217         v4l2_ctrl_handler_free(hdl);
1218         v4l2_fh_exit(&ctx->fh);
1219         kfree(ctx);
1220         goto open_unlock;
1221     }
1222 
1223     v4l2_fh_add(&ctx->fh);
1224     atomic_inc(&dev->num_inst);
1225 
1226     dprintk(dev, 1, "Created instance: %p, m2m_ctx: %p\n",
1227         ctx, ctx->fh.m2m_ctx);
1228 
1229 open_unlock:
1230     mutex_unlock(&dev->dev_mutex);
1231     return rc;
1232 }
1233 
1234 static int vim2m_release(struct file *file)
1235 {
1236     struct vim2m_dev *dev = video_drvdata(file);
1237     struct vim2m_ctx *ctx = file2ctx(file);
1238 
1239     dprintk(dev, 1, "Releasing instance %p\n", ctx);
1240 
1241     v4l2_fh_del(&ctx->fh);
1242     v4l2_fh_exit(&ctx->fh);
1243     v4l2_ctrl_handler_free(&ctx->hdl);
1244     mutex_lock(&dev->dev_mutex);
1245     v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
1246     mutex_unlock(&dev->dev_mutex);
1247     kfree(ctx);
1248 
1249     atomic_dec(&dev->num_inst);
1250 
1251     return 0;
1252 }
1253 
1254 static void vim2m_device_release(struct video_device *vdev)
1255 {
1256     struct vim2m_dev *dev = container_of(vdev, struct vim2m_dev, vfd);
1257 
1258     v4l2_device_unregister(&dev->v4l2_dev);
1259     v4l2_m2m_release(dev->m2m_dev);
1260 #ifdef CONFIG_MEDIA_CONTROLLER
1261     media_device_cleanup(&dev->mdev);
1262 #endif
1263     kfree(dev);
1264 }
1265 
1266 static const struct v4l2_file_operations vim2m_fops = {
1267     .owner      = THIS_MODULE,
1268     .open       = vim2m_open,
1269     .release    = vim2m_release,
1270     .poll       = v4l2_m2m_fop_poll,
1271     .unlocked_ioctl = video_ioctl2,
1272     .mmap       = v4l2_m2m_fop_mmap,
1273 };
1274 
1275 static const struct video_device vim2m_videodev = {
1276     .name       = MEM2MEM_NAME,
1277     .vfl_dir    = VFL_DIR_M2M,
1278     .fops       = &vim2m_fops,
1279     .ioctl_ops  = &vim2m_ioctl_ops,
1280     .minor      = -1,
1281     .release    = vim2m_device_release,
1282     .device_caps    = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
1283 };
1284 
1285 static const struct v4l2_m2m_ops m2m_ops = {
1286     .device_run = device_run,
1287     .job_ready  = job_ready,
1288     .job_abort  = job_abort,
1289 };
1290 
1291 static const struct media_device_ops m2m_media_ops = {
1292     .req_validate = vb2_request_validate,
1293     .req_queue = v4l2_m2m_request_queue,
1294 };
1295 
1296 static int vim2m_probe(struct platform_device *pdev)
1297 {
1298     struct vim2m_dev *dev;
1299     struct video_device *vfd;
1300     int ret;
1301 
1302     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1303     if (!dev)
1304         return -ENOMEM;
1305 
1306     ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1307     if (ret)
1308         goto error_free;
1309 
1310     atomic_set(&dev->num_inst, 0);
1311     mutex_init(&dev->dev_mutex);
1312 
1313     dev->vfd = vim2m_videodev;
1314     vfd = &dev->vfd;
1315     vfd->lock = &dev->dev_mutex;
1316     vfd->v4l2_dev = &dev->v4l2_dev;
1317 
1318     video_set_drvdata(vfd, dev);
1319     v4l2_info(&dev->v4l2_dev,
1320           "Device registered as /dev/video%d\n", vfd->num);
1321 
1322     platform_set_drvdata(pdev, dev);
1323 
1324     dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
1325     if (IS_ERR(dev->m2m_dev)) {
1326         v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
1327         ret = PTR_ERR(dev->m2m_dev);
1328         dev->m2m_dev = NULL;
1329         goto error_dev;
1330     }
1331 
1332 #ifdef CONFIG_MEDIA_CONTROLLER
1333     dev->mdev.dev = &pdev->dev;
1334     strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model));
1335     strscpy(dev->mdev.bus_info, "platform:vim2m",
1336         sizeof(dev->mdev.bus_info));
1337     media_device_init(&dev->mdev);
1338     dev->mdev.ops = &m2m_media_ops;
1339     dev->v4l2_dev.mdev = &dev->mdev;
1340 #endif
1341 
1342     ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
1343     if (ret) {
1344         v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1345         goto error_m2m;
1346     }
1347 
1348 #ifdef CONFIG_MEDIA_CONTROLLER
1349     ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
1350                          MEDIA_ENT_F_PROC_VIDEO_SCALER);
1351     if (ret) {
1352         v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1353         goto error_v4l2;
1354     }
1355 
1356     ret = media_device_register(&dev->mdev);
1357     if (ret) {
1358         v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1359         goto error_m2m_mc;
1360     }
1361 #endif
1362     return 0;
1363 
1364 #ifdef CONFIG_MEDIA_CONTROLLER
1365 error_m2m_mc:
1366     v4l2_m2m_unregister_media_controller(dev->m2m_dev);
1367 #endif
1368 error_v4l2:
1369     video_unregister_device(&dev->vfd);
1370     /* vim2m_device_release called by video_unregister_device to release various objects */
1371     return ret;
1372 error_m2m:
1373     v4l2_m2m_release(dev->m2m_dev);
1374 error_dev:
1375     v4l2_device_unregister(&dev->v4l2_dev);
1376 error_free:
1377     kfree(dev);
1378 
1379     return ret;
1380 }
1381 
1382 static int vim2m_remove(struct platform_device *pdev)
1383 {
1384     struct vim2m_dev *dev = platform_get_drvdata(pdev);
1385 
1386     v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
1387 
1388 #ifdef CONFIG_MEDIA_CONTROLLER
1389     media_device_unregister(&dev->mdev);
1390     v4l2_m2m_unregister_media_controller(dev->m2m_dev);
1391 #endif
1392     video_unregister_device(&dev->vfd);
1393 
1394     return 0;
1395 }
1396 
1397 static struct platform_driver vim2m_pdrv = {
1398     .probe      = vim2m_probe,
1399     .remove     = vim2m_remove,
1400     .driver     = {
1401         .name   = MEM2MEM_NAME,
1402     },
1403 };
1404 
1405 static void __exit vim2m_exit(void)
1406 {
1407     platform_driver_unregister(&vim2m_pdrv);
1408     platform_device_unregister(&vim2m_pdev);
1409 }
1410 
1411 static int __init vim2m_init(void)
1412 {
1413     int ret;
1414 
1415     ret = platform_device_register(&vim2m_pdev);
1416     if (ret)
1417         return ret;
1418 
1419     ret = platform_driver_register(&vim2m_pdrv);
1420     if (ret)
1421         platform_device_unregister(&vim2m_pdev);
1422 
1423     return ret;
1424 }
1425 
1426 module_init(vim2m_init);
1427 module_exit(vim2m_exit);