linux/drivers/media/platform/mem2mem_testdev.c
<<
>>
Prefs
   1/*
   2 * A virtual v4l2-mem2mem example device.
   3 *
   4 * This is a virtual device driver for testing mem-to-mem videobuf framework.
   5 * It simulates a device that uses memory buffers for both source and
   6 * destination, processes the data and issues an "irq" (simulated by a timer).
   7 * The device is capable of multi-instance, multi-buffer-per-transaction
   8 * operation (via the mem2mem framework).
   9 *
  10 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
  11 * Pawel Osciak, <pawel@osciak.com>
  12 * Marek Szyprowski, <m.szyprowski@samsung.com>
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License as published by the
  16 * Free Software Foundation; either version 2 of the
  17 * License, or (at your option) any later version
  18 */
  19#include <linux/module.h>
  20#include <linux/delay.h>
  21#include <linux/fs.h>
  22#include <linux/timer.h>
  23#include <linux/sched.h>
  24#include <linux/slab.h>
  25
  26#include <linux/platform_device.h>
  27#include <media/v4l2-mem2mem.h>
  28#include <media/v4l2-device.h>
  29#include <media/v4l2-ioctl.h>
  30#include <media/v4l2-ctrls.h>
  31#include <media/v4l2-event.h>
  32#include <media/videobuf2-vmalloc.h>
  33
  34#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev"
  35
  36MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
  37MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
  38MODULE_LICENSE("GPL");
  39MODULE_VERSION("0.1.1");
  40
  41static unsigned debug;
  42module_param(debug, uint, 0644);
  43MODULE_PARM_DESC(debug, "activates debug info");
  44
  45#define MIN_W 32
  46#define MIN_H 32
  47#define MAX_W 640
  48#define MAX_H 480
  49#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */
  50
  51/* Flags that indicate a format can be used for capture/output */
  52#define MEM2MEM_CAPTURE (1 << 0)
  53#define MEM2MEM_OUTPUT  (1 << 1)
  54
  55#define MEM2MEM_NAME            "m2m-testdev"
  56
  57/* Per queue */
  58#define MEM2MEM_DEF_NUM_BUFS    VIDEO_MAX_FRAME
  59/* In bytes, per queue */
  60#define MEM2MEM_VID_MEM_LIMIT   (16 * 1024 * 1024)
  61
  62/* Default transaction time in msec */
  63#define MEM2MEM_DEF_TRANSTIME   1000
  64/* Default number of buffers per transaction */
  65#define MEM2MEM_DEF_TRANSLEN    1
  66#define MEM2MEM_COLOR_STEP      (0xff >> 4)
  67#define MEM2MEM_NUM_TILES       8
  68
  69/* Flags that indicate processing mode */
  70#define MEM2MEM_HFLIP   (1 << 0)
  71#define MEM2MEM_VFLIP   (1 << 1)
  72
  73#define dprintk(dev, fmt, arg...) \
  74        v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
  75
  76
  77static void m2mtest_dev_release(struct device *dev)
  78{}
  79
  80static struct platform_device m2mtest_pdev = {
  81        .name           = MEM2MEM_NAME,
  82        .dev.release    = m2mtest_dev_release,
  83};
  84
  85struct m2mtest_fmt {
  86        char    *name;
  87        u32     fourcc;
  88        int     depth;
  89        /* Types the format can be used for */
  90        u32     types;
  91};
  92
  93static struct m2mtest_fmt formats[] = {
  94        {
  95                .name   = "RGB565 (BE)",
  96                .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
  97                .depth  = 16,
  98                /* Both capture and output format */
  99                .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
 100        },
 101        {
 102                .name   = "4:2:2, packed, YUYV",
 103                .fourcc = V4L2_PIX_FMT_YUYV,
 104                .depth  = 16,
 105                /* Output-only format */
 106                .types  = MEM2MEM_OUTPUT,
 107        },
 108};
 109
 110#define NUM_FORMATS ARRAY_SIZE(formats)
 111
 112/* Per-queue, driver-specific private data */
 113struct m2mtest_q_data {
 114        unsigned int            width;
 115        unsigned int            height;
 116        unsigned int            sizeimage;
 117        struct m2mtest_fmt      *fmt;
 118};
 119
 120enum {
 121        V4L2_M2M_SRC = 0,
 122        V4L2_M2M_DST = 1,
 123};
 124
 125#define V4L2_CID_TRANS_TIME_MSEC        (V4L2_CID_USER_BASE + 0x1000)
 126#define V4L2_CID_TRANS_NUM_BUFS         (V4L2_CID_USER_BASE + 0x1001)
 127
 128static struct m2mtest_fmt *find_format(struct v4l2_format *f)
 129{
 130        struct m2mtest_fmt *fmt;
 131        unsigned int k;
 132
 133        for (k = 0; k < NUM_FORMATS; k++) {
 134                fmt = &formats[k];
 135                if (fmt->fourcc == f->fmt.pix.pixelformat)
 136                        break;
 137        }
 138
 139        if (k == NUM_FORMATS)
 140                return NULL;
 141
 142        return &formats[k];
 143}
 144
 145struct m2mtest_dev {
 146        struct v4l2_device      v4l2_dev;
 147        struct video_device     *vfd;
 148
 149        atomic_t                num_inst;
 150        struct mutex            dev_mutex;
 151        spinlock_t              irqlock;
 152
 153        struct timer_list       timer;
 154
 155        struct v4l2_m2m_dev     *m2m_dev;
 156};
 157
 158struct m2mtest_ctx {
 159        struct v4l2_fh          fh;
 160        struct m2mtest_dev      *dev;
 161
 162        struct v4l2_ctrl_handler hdl;
 163
 164        /* Processed buffers in this transaction */
 165        u8                      num_processed;
 166
 167        /* Transaction length (i.e. how many buffers per transaction) */
 168        u32                     translen;
 169        /* Transaction time (i.e. simulated processing time) in milliseconds */
 170        u32                     transtime;
 171
 172        /* Abort requested by m2m */
 173        int                     aborting;
 174
 175        /* Processing mode */
 176        int                     mode;
 177
 178        enum v4l2_colorspace    colorspace;
 179
 180        struct v4l2_m2m_ctx     *m2m_ctx;
 181
 182        /* Source and destination queue data */
 183        struct m2mtest_q_data   q_data[2];
 184};
 185
 186static inline struct m2mtest_ctx *file2ctx(struct file *file)
 187{
 188        return container_of(file->private_data, struct m2mtest_ctx, fh);
 189}
 190
 191static struct m2mtest_q_data *get_q_data(struct m2mtest_ctx *ctx,
 192                                         enum v4l2_buf_type type)
 193{
 194        switch (type) {
 195        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 196                return &ctx->q_data[V4L2_M2M_SRC];
 197        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 198                return &ctx->q_data[V4L2_M2M_DST];
 199        default:
 200                BUG();
 201        }
 202        return NULL;
 203}
 204
 205
 206static int device_process(struct m2mtest_ctx *ctx,
 207                          struct vb2_buffer *in_vb,
 208                          struct vb2_buffer *out_vb)
 209{
 210        struct m2mtest_dev *dev = ctx->dev;
 211        struct m2mtest_q_data *q_data;
 212        u8 *p_in, *p_out;
 213        int x, y, t, w;
 214        int tile_w, bytes_left;
 215        int width, height, bytesperline;
 216
 217        q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 218
 219        width   = q_data->width;
 220        height  = q_data->height;
 221        bytesperline    = (q_data->width * q_data->fmt->depth) >> 3;
 222
 223        p_in = vb2_plane_vaddr(in_vb, 0);
 224        p_out = vb2_plane_vaddr(out_vb, 0);
 225        if (!p_in || !p_out) {
 226                v4l2_err(&dev->v4l2_dev,
 227                         "Acquiring kernel pointers to buffers failed\n");
 228                return -EFAULT;
 229        }
 230
 231        if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) {
 232                v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
 233                return -EINVAL;
 234        }
 235
 236        tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
 237                / MEM2MEM_NUM_TILES;
 238        bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
 239        w = 0;
 240
 241        memcpy(&out_vb->v4l2_buf.timestamp,
 242                        &in_vb->v4l2_buf.timestamp,
 243                        sizeof(struct timeval));
 244
 245        switch (ctx->mode) {
 246        case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
 247                p_out += bytesperline * height - bytes_left;
 248                for (y = 0; y < height; ++y) {
 249                        for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
 250                                if (w & 0x1) {
 251                                        for (x = 0; x < tile_w; ++x)
 252                                                *--p_out = *p_in++ +
 253                                                        MEM2MEM_COLOR_STEP;
 254                                } else {
 255                                        for (x = 0; x < tile_w; ++x)
 256                                                *--p_out = *p_in++ -
 257                                                        MEM2MEM_COLOR_STEP;
 258                                }
 259                                ++w;
 260                        }
 261                        p_in += bytes_left;
 262                        p_out -= bytes_left;
 263                }
 264                break;
 265
 266        case MEM2MEM_HFLIP:
 267                for (y = 0; y < height; ++y) {
 268                        p_out += MEM2MEM_NUM_TILES * tile_w;
 269                        for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
 270                                if (w & 0x01) {
 271                                        for (x = 0; x < tile_w; ++x)
 272                                                *--p_out = *p_in++ +
 273                                                        MEM2MEM_COLOR_STEP;
 274                                } else {
 275                                        for (x = 0; x < tile_w; ++x)
 276                                                *--p_out = *p_in++ -
 277                                                        MEM2MEM_COLOR_STEP;
 278                                }
 279                                ++w;
 280                        }
 281                        p_in += bytes_left;
 282                        p_out += bytesperline;
 283                }
 284                break;
 285
 286        case MEM2MEM_VFLIP:
 287                p_out += bytesperline * (height - 1);
 288                for (y = 0; y < height; ++y) {
 289                        for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
 290                                if (w & 0x1) {
 291                                        for (x = 0; x < tile_w; ++x)
 292                                                *p_out++ = *p_in++ +
 293                                                        MEM2MEM_COLOR_STEP;
 294                                } else {
 295                                        for (x = 0; x < tile_w; ++x)
 296                                                *p_out++ = *p_in++ -
 297                                                        MEM2MEM_COLOR_STEP;
 298                                }
 299                                ++w;
 300                        }
 301                        p_in += bytes_left;
 302                        p_out += bytes_left - 2 * bytesperline;
 303                }
 304                break;
 305
 306        default:
 307                for (y = 0; y < height; ++y) {
 308                        for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
 309                                if (w & 0x1) {
 310                                        for (x = 0; x < tile_w; ++x)
 311                                                *p_out++ = *p_in++ +
 312                                                        MEM2MEM_COLOR_STEP;
 313                                } else {
 314                                        for (x = 0; x < tile_w; ++x)
 315                                                *p_out++ = *p_in++ -
 316                                                        MEM2MEM_COLOR_STEP;
 317                                }
 318                                ++w;
 319                        }
 320                        p_in += bytes_left;
 321                        p_out += bytes_left;
 322                }
 323        }
 324
 325        return 0;
 326}
 327
 328static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout)
 329{
 330        dprintk(dev, "Scheduling a simulated irq\n");
 331        mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
 332}
 333
 334/*
 335 * mem2mem callbacks
 336 */
 337
 338/**
 339 * job_ready() - check whether an instance is ready to be scheduled to run
 340 */
 341static int job_ready(void *priv)
 342{
 343        struct m2mtest_ctx *ctx = priv;
 344
 345        if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen
 346            || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) {
 347                dprintk(ctx->dev, "Not enough buffers available\n");
 348                return 0;
 349        }
 350
 351        return 1;
 352}
 353
 354static void job_abort(void *priv)
 355{
 356        struct m2mtest_ctx *ctx = priv;
 357
 358        /* Will cancel the transaction in the next interrupt handler */
 359        ctx->aborting = 1;
 360}
 361
 362static void m2mtest_lock(void *priv)
 363{
 364        struct m2mtest_ctx *ctx = priv;
 365        struct m2mtest_dev *dev = ctx->dev;
 366        mutex_lock(&dev->dev_mutex);
 367}
 368
 369static void m2mtest_unlock(void *priv)
 370{
 371        struct m2mtest_ctx *ctx = priv;
 372        struct m2mtest_dev *dev = ctx->dev;
 373        mutex_unlock(&dev->dev_mutex);
 374}
 375
 376
 377/* device_run() - prepares and starts the device
 378 *
 379 * This simulates all the immediate preparations required before starting
 380 * a device. This will be called by the framework when it decides to schedule
 381 * a particular instance.
 382 */
 383static void device_run(void *priv)
 384{
 385        struct m2mtest_ctx *ctx = priv;
 386        struct m2mtest_dev *dev = ctx->dev;
 387        struct vb2_buffer *src_buf, *dst_buf;
 388
 389        src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
 390        dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
 391
 392        device_process(ctx, src_buf, dst_buf);
 393
 394        /* Run a timer, which simulates a hardware irq  */
 395        schedule_irq(dev, ctx->transtime);
 396}
 397
 398static void device_isr(unsigned long priv)
 399{
 400        struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv;
 401        struct m2mtest_ctx *curr_ctx;
 402        struct vb2_buffer *src_vb, *dst_vb;
 403        unsigned long flags;
 404
 405        curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev);
 406
 407        if (NULL == curr_ctx) {
 408                pr_err("Instance released before the end of transaction\n");
 409                return;
 410        }
 411
 412        src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
 413        dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
 414
 415        curr_ctx->num_processed++;
 416
 417        spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
 418        v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
 419        v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
 420        spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
 421
 422        if (curr_ctx->num_processed == curr_ctx->translen
 423            || curr_ctx->aborting) {
 424                dprintk(curr_ctx->dev, "Finishing transaction\n");
 425                curr_ctx->num_processed = 0;
 426                v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
 427        } else {
 428                device_run(curr_ctx);
 429        }
 430}
 431
 432/*
 433 * video ioctls
 434 */
 435static int vidioc_querycap(struct file *file, void *priv,
 436                           struct v4l2_capability *cap)
 437{
 438        strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
 439        strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
 440        snprintf(cap->bus_info, sizeof(cap->bus_info),
 441                        "platform:%s", MEM2MEM_NAME);
 442        cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
 443        cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 444        return 0;
 445}
 446
 447static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
 448{
 449        int i, num;
 450        struct m2mtest_fmt *fmt;
 451
 452        num = 0;
 453
 454        for (i = 0; i < NUM_FORMATS; ++i) {
 455                if (formats[i].types & type) {
 456                        /* index-th format of type type found ? */
 457                        if (num == f->index)
 458                                break;
 459                        /* Correct type but haven't reached our index yet,
 460                         * just increment per-type index */
 461                        ++num;
 462                }
 463        }
 464
 465        if (i < NUM_FORMATS) {
 466                /* Format found */
 467                fmt = &formats[i];
 468                strncpy(f->description, fmt->name, sizeof(f->description) - 1);
 469                f->pixelformat = fmt->fourcc;
 470                return 0;
 471        }
 472
 473        /* Format not found */
 474        return -EINVAL;
 475}
 476
 477static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 478                                   struct v4l2_fmtdesc *f)
 479{
 480        return enum_fmt(f, MEM2MEM_CAPTURE);
 481}
 482
 483static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
 484                                   struct v4l2_fmtdesc *f)
 485{
 486        return enum_fmt(f, MEM2MEM_OUTPUT);
 487}
 488
 489static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
 490{
 491        struct vb2_queue *vq;
 492        struct m2mtest_q_data *q_data;
 493
 494        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 495        if (!vq)
 496                return -EINVAL;
 497
 498        q_data = get_q_data(ctx, f->type);
 499
 500        f->fmt.pix.width        = q_data->width;
 501        f->fmt.pix.height       = q_data->height;
 502        f->fmt.pix.field        = V4L2_FIELD_NONE;
 503        f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
 504        f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
 505        f->fmt.pix.sizeimage    = q_data->sizeimage;
 506        f->fmt.pix.colorspace   = ctx->colorspace;
 507
 508        return 0;
 509}
 510
 511static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
 512                                struct v4l2_format *f)
 513{
 514        return vidioc_g_fmt(file2ctx(file), f);
 515}
 516
 517static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 518                                struct v4l2_format *f)
 519{
 520        return vidioc_g_fmt(file2ctx(file), f);
 521}
 522
 523static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
 524{
 525        enum v4l2_field field;
 526
 527        field = f->fmt.pix.field;
 528
 529        if (field == V4L2_FIELD_ANY)
 530                field = V4L2_FIELD_NONE;
 531        else if (V4L2_FIELD_NONE != field)
 532                return -EINVAL;
 533
 534        /* V4L2 specification suggests the driver corrects the format struct
 535         * if any of the dimensions is unsupported */
 536        f->fmt.pix.field = field;
 537
 538        if (f->fmt.pix.height < MIN_H)
 539                f->fmt.pix.height = MIN_H;
 540        else if (f->fmt.pix.height > MAX_H)
 541                f->fmt.pix.height = MAX_H;
 542
 543        if (f->fmt.pix.width < MIN_W)
 544                f->fmt.pix.width = MIN_W;
 545        else if (f->fmt.pix.width > MAX_W)
 546                f->fmt.pix.width = MAX_W;
 547
 548        f->fmt.pix.width &= ~DIM_ALIGN_MASK;
 549        f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
 550        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
 551
 552        return 0;
 553}
 554
 555static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 556                                  struct v4l2_format *f)
 557{
 558        struct m2mtest_fmt *fmt;
 559        struct m2mtest_ctx *ctx = file2ctx(file);
 560
 561        fmt = find_format(f);
 562        if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
 563                v4l2_err(&ctx->dev->v4l2_dev,
 564                         "Fourcc format (0x%08x) invalid.\n",
 565                         f->fmt.pix.pixelformat);
 566                return -EINVAL;
 567        }
 568        f->fmt.pix.colorspace = ctx->colorspace;
 569
 570        return vidioc_try_fmt(f, fmt);
 571}
 572
 573static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
 574                                  struct v4l2_format *f)
 575{
 576        struct m2mtest_fmt *fmt;
 577        struct m2mtest_ctx *ctx = file2ctx(file);
 578
 579        fmt = find_format(f);
 580        if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
 581                v4l2_err(&ctx->dev->v4l2_dev,
 582                         "Fourcc format (0x%08x) invalid.\n",
 583                         f->fmt.pix.pixelformat);
 584                return -EINVAL;
 585        }
 586        if (!f->fmt.pix.colorspace)
 587                f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
 588
 589        return vidioc_try_fmt(f, fmt);
 590}
 591
 592static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
 593{
 594        struct m2mtest_q_data *q_data;
 595        struct vb2_queue *vq;
 596
 597        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 598        if (!vq)
 599                return -EINVAL;
 600
 601        q_data = get_q_data(ctx, f->type);
 602        if (!q_data)
 603                return -EINVAL;
 604
 605        if (vb2_is_busy(vq)) {
 606                v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
 607                return -EBUSY;
 608        }
 609
 610        q_data->fmt             = find_format(f);
 611        q_data->width           = f->fmt.pix.width;
 612        q_data->height          = f->fmt.pix.height;
 613        q_data->sizeimage       = q_data->width * q_data->height
 614                                * q_data->fmt->depth >> 3;
 615
 616        dprintk(ctx->dev,
 617                "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
 618                f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
 619
 620        return 0;
 621}
 622
 623static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 624                                struct v4l2_format *f)
 625{
 626        int ret;
 627
 628        ret = vidioc_try_fmt_vid_cap(file, priv, f);
 629        if (ret)
 630                return ret;
 631
 632        return vidioc_s_fmt(file2ctx(file), f);
 633}
 634
 635static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
 636                                struct v4l2_format *f)
 637{
 638        struct m2mtest_ctx *ctx = file2ctx(file);
 639        int ret;
 640
 641        ret = vidioc_try_fmt_vid_out(file, priv, f);
 642        if (ret)
 643                return ret;
 644
 645        ret = vidioc_s_fmt(file2ctx(file), f);
 646        if (!ret)
 647                ctx->colorspace = f->fmt.pix.colorspace;
 648        return ret;
 649}
 650
 651static int vidioc_reqbufs(struct file *file, void *priv,
 652                          struct v4l2_requestbuffers *reqbufs)
 653{
 654        struct m2mtest_ctx *ctx = file2ctx(file);
 655
 656        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 657}
 658
 659static int vidioc_querybuf(struct file *file, void *priv,
 660                           struct v4l2_buffer *buf)
 661{
 662        struct m2mtest_ctx *ctx = file2ctx(file);
 663
 664        return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
 665}
 666
 667static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 668{
 669        struct m2mtest_ctx *ctx = file2ctx(file);
 670
 671        return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 672}
 673
 674static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 675{
 676        struct m2mtest_ctx *ctx = file2ctx(file);
 677
 678        return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
 679}
 680
 681static int vidioc_streamon(struct file *file, void *priv,
 682                           enum v4l2_buf_type type)
 683{
 684        struct m2mtest_ctx *ctx = file2ctx(file);
 685
 686        return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 687}
 688
 689static int vidioc_streamoff(struct file *file, void *priv,
 690                            enum v4l2_buf_type type)
 691{
 692        struct m2mtest_ctx *ctx = file2ctx(file);
 693
 694        return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
 695}
 696
 697static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl)
 698{
 699        struct m2mtest_ctx *ctx =
 700                container_of(ctrl->handler, struct m2mtest_ctx, hdl);
 701
 702        switch (ctrl->id) {
 703        case V4L2_CID_HFLIP:
 704                if (ctrl->val)
 705                        ctx->mode |= MEM2MEM_HFLIP;
 706                else
 707                        ctx->mode &= ~MEM2MEM_HFLIP;
 708                break;
 709
 710        case V4L2_CID_VFLIP:
 711                if (ctrl->val)
 712                        ctx->mode |= MEM2MEM_VFLIP;
 713                else
 714                        ctx->mode &= ~MEM2MEM_VFLIP;
 715                break;
 716
 717        case V4L2_CID_TRANS_TIME_MSEC:
 718                ctx->transtime = ctrl->val;
 719                break;
 720
 721        case V4L2_CID_TRANS_NUM_BUFS:
 722                ctx->translen = ctrl->val;
 723                break;
 724
 725        default:
 726                v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
 727                return -EINVAL;
 728        }
 729
 730        return 0;
 731}
 732
 733static const struct v4l2_ctrl_ops m2mtest_ctrl_ops = {
 734        .s_ctrl = m2mtest_s_ctrl,
 735};
 736
 737
 738static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
 739        .vidioc_querycap        = vidioc_querycap,
 740
 741        .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 742        .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
 743        .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
 744        .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
 745
 746        .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
 747        .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
 748        .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
 749        .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
 750
 751        .vidioc_reqbufs         = vidioc_reqbufs,
 752        .vidioc_querybuf        = vidioc_querybuf,
 753
 754        .vidioc_qbuf            = vidioc_qbuf,
 755        .vidioc_dqbuf           = vidioc_dqbuf,
 756
 757        .vidioc_streamon        = vidioc_streamon,
 758        .vidioc_streamoff       = vidioc_streamoff,
 759        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 760        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 761};
 762
 763
 764/*
 765 * Queue operations
 766 */
 767
 768static int m2mtest_queue_setup(struct vb2_queue *vq,
 769                                const struct v4l2_format *fmt,
 770                                unsigned int *nbuffers, unsigned int *nplanes,
 771                                unsigned int sizes[], void *alloc_ctxs[])
 772{
 773        struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq);
 774        struct m2mtest_q_data *q_data;
 775        unsigned int size, count = *nbuffers;
 776
 777        q_data = get_q_data(ctx, vq->type);
 778
 779        size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
 780
 781        while (size * count > MEM2MEM_VID_MEM_LIMIT)
 782                (count)--;
 783
 784        *nplanes = 1;
 785        *nbuffers = count;
 786        sizes[0] = size;
 787
 788        /*
 789         * videobuf2-vmalloc allocator is context-less so no need to set
 790         * alloc_ctxs array.
 791         */
 792
 793        dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
 794
 795        return 0;
 796}
 797
 798static int m2mtest_buf_prepare(struct vb2_buffer *vb)
 799{
 800        struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 801        struct m2mtest_q_data *q_data;
 802
 803        dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
 804
 805        q_data = get_q_data(ctx, vb->vb2_queue->type);
 806
 807        if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
 808                dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
 809                                __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage);
 810                return -EINVAL;
 811        }
 812
 813        vb2_set_plane_payload(vb, 0, q_data->sizeimage);
 814
 815        return 0;
 816}
 817
 818static void m2mtest_buf_queue(struct vb2_buffer *vb)
 819{
 820        struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 821        v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
 822}
 823
 824static void m2mtest_wait_prepare(struct vb2_queue *q)
 825{
 826        struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
 827        m2mtest_unlock(ctx);
 828}
 829
 830static void m2mtest_wait_finish(struct vb2_queue *q)
 831{
 832        struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
 833        m2mtest_lock(ctx);
 834}
 835
 836static struct vb2_ops m2mtest_qops = {
 837        .queue_setup     = m2mtest_queue_setup,
 838        .buf_prepare     = m2mtest_buf_prepare,
 839        .buf_queue       = m2mtest_buf_queue,
 840        .wait_prepare    = m2mtest_wait_prepare,
 841        .wait_finish     = m2mtest_wait_finish,
 842};
 843
 844static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 845{
 846        struct m2mtest_ctx *ctx = priv;
 847        int ret;
 848
 849        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
 850        src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 851        src_vq->drv_priv = ctx;
 852        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 853        src_vq->ops = &m2mtest_qops;
 854        src_vq->mem_ops = &vb2_vmalloc_memops;
 855        src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 856
 857        ret = vb2_queue_init(src_vq);
 858        if (ret)
 859                return ret;
 860
 861        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 862        dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 863        dst_vq->drv_priv = ctx;
 864        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 865        dst_vq->ops = &m2mtest_qops;
 866        dst_vq->mem_ops = &vb2_vmalloc_memops;
 867        dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 868
 869        return vb2_queue_init(dst_vq);
 870}
 871
 872static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = {
 873        .ops = &m2mtest_ctrl_ops,
 874        .id = V4L2_CID_TRANS_TIME_MSEC,
 875        .name = "Transaction Time (msec)",
 876        .type = V4L2_CTRL_TYPE_INTEGER,
 877        .def = 1001,
 878        .min = 1,
 879        .max = 10001,
 880        .step = 100,
 881};
 882
 883static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = {
 884        .ops = &m2mtest_ctrl_ops,
 885        .id = V4L2_CID_TRANS_NUM_BUFS,
 886        .name = "Buffers Per Transaction",
 887        .type = V4L2_CTRL_TYPE_INTEGER,
 888        .def = 1,
 889        .min = 1,
 890        .max = MEM2MEM_DEF_NUM_BUFS,
 891        .step = 1,
 892};
 893
 894/*
 895 * File operations
 896 */
 897static int m2mtest_open(struct file *file)
 898{
 899        struct m2mtest_dev *dev = video_drvdata(file);
 900        struct m2mtest_ctx *ctx = NULL;
 901        struct v4l2_ctrl_handler *hdl;
 902        int rc = 0;
 903
 904        if (mutex_lock_interruptible(&dev->dev_mutex))
 905                return -ERESTARTSYS;
 906        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 907        if (!ctx) {
 908                rc = -ENOMEM;
 909                goto open_unlock;
 910        }
 911
 912        v4l2_fh_init(&ctx->fh, video_devdata(file));
 913        file->private_data = &ctx->fh;
 914        ctx->dev = dev;
 915        hdl = &ctx->hdl;
 916        v4l2_ctrl_handler_init(hdl, 4);
 917        v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
 918        v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
 919        v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_time_msec, NULL);
 920        v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_num_bufs, NULL);
 921        if (hdl->error) {
 922                rc = hdl->error;
 923                v4l2_ctrl_handler_free(hdl);
 924                goto open_unlock;
 925        }
 926        ctx->fh.ctrl_handler = hdl;
 927        v4l2_ctrl_handler_setup(hdl);
 928
 929        ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
 930        ctx->q_data[V4L2_M2M_SRC].width = 640;
 931        ctx->q_data[V4L2_M2M_SRC].height = 480;
 932        ctx->q_data[V4L2_M2M_SRC].sizeimage =
 933                ctx->q_data[V4L2_M2M_SRC].width *
 934                ctx->q_data[V4L2_M2M_SRC].height *
 935                (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3);
 936        ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
 937        ctx->colorspace = V4L2_COLORSPACE_REC709;
 938
 939        ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
 940
 941        if (IS_ERR(ctx->m2m_ctx)) {
 942                rc = PTR_ERR(ctx->m2m_ctx);
 943
 944                v4l2_ctrl_handler_free(hdl);
 945                kfree(ctx);
 946                goto open_unlock;
 947        }
 948
 949        v4l2_fh_add(&ctx->fh);
 950        atomic_inc(&dev->num_inst);
 951
 952        dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
 953
 954open_unlock:
 955        mutex_unlock(&dev->dev_mutex);
 956        return rc;
 957}
 958
 959static int m2mtest_release(struct file *file)
 960{
 961        struct m2mtest_dev *dev = video_drvdata(file);
 962        struct m2mtest_ctx *ctx = file2ctx(file);
 963
 964        dprintk(dev, "Releasing instance %p\n", ctx);
 965
 966        v4l2_fh_del(&ctx->fh);
 967        v4l2_fh_exit(&ctx->fh);
 968        v4l2_ctrl_handler_free(&ctx->hdl);
 969        mutex_lock(&dev->dev_mutex);
 970        v4l2_m2m_ctx_release(ctx->m2m_ctx);
 971        mutex_unlock(&dev->dev_mutex);
 972        kfree(ctx);
 973
 974        atomic_dec(&dev->num_inst);
 975
 976        return 0;
 977}
 978
 979static unsigned int m2mtest_poll(struct file *file,
 980                                 struct poll_table_struct *wait)
 981{
 982        struct m2mtest_ctx *ctx = file2ctx(file);
 983
 984        return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 985}
 986
 987static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
 988{
 989        struct m2mtest_dev *dev = video_drvdata(file);
 990        struct m2mtest_ctx *ctx = file2ctx(file);
 991        int res;
 992
 993        if (mutex_lock_interruptible(&dev->dev_mutex))
 994                return -ERESTARTSYS;
 995        res = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 996        mutex_unlock(&dev->dev_mutex);
 997        return res;
 998}
 999
1000static const struct v4l2_file_operations m2mtest_fops = {
1001        .owner          = THIS_MODULE,
1002        .open           = m2mtest_open,
1003        .release        = m2mtest_release,
1004        .poll           = m2mtest_poll,
1005        .unlocked_ioctl = video_ioctl2,
1006        .mmap           = m2mtest_mmap,
1007};
1008
1009static struct video_device m2mtest_videodev = {
1010        .name           = MEM2MEM_NAME,
1011        .vfl_dir        = VFL_DIR_M2M,
1012        .fops           = &m2mtest_fops,
1013        .ioctl_ops      = &m2mtest_ioctl_ops,
1014        .minor          = -1,
1015        .release        = video_device_release,
1016};
1017
1018static struct v4l2_m2m_ops m2m_ops = {
1019        .device_run     = device_run,
1020        .job_ready      = job_ready,
1021        .job_abort      = job_abort,
1022        .lock           = m2mtest_lock,
1023        .unlock         = m2mtest_unlock,
1024};
1025
1026static int m2mtest_probe(struct platform_device *pdev)
1027{
1028        struct m2mtest_dev *dev;
1029        struct video_device *vfd;
1030        int ret;
1031
1032        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
1033        if (!dev)
1034                return -ENOMEM;
1035
1036        spin_lock_init(&dev->irqlock);
1037
1038        ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1039        if (ret)
1040                return ret;
1041
1042        atomic_set(&dev->num_inst, 0);
1043        mutex_init(&dev->dev_mutex);
1044
1045        vfd = video_device_alloc();
1046        if (!vfd) {
1047                v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
1048                ret = -ENOMEM;
1049                goto unreg_dev;
1050        }
1051
1052        *vfd = m2mtest_videodev;
1053        vfd->lock = &dev->dev_mutex;
1054
1055        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1056        if (ret) {
1057                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
1058                goto rel_vdev;
1059        }
1060
1061        video_set_drvdata(vfd, dev);
1062        snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name);
1063        dev->vfd = vfd;
1064        v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
1065                        "Device registered as /dev/video%d\n", vfd->num);
1066
1067        setup_timer(&dev->timer, device_isr, (long)dev);
1068        platform_set_drvdata(pdev, dev);
1069
1070        dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
1071        if (IS_ERR(dev->m2m_dev)) {
1072                v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
1073                ret = PTR_ERR(dev->m2m_dev);
1074                goto err_m2m;
1075        }
1076
1077        return 0;
1078
1079err_m2m:
1080        v4l2_m2m_release(dev->m2m_dev);
1081        video_unregister_device(dev->vfd);
1082rel_vdev:
1083        video_device_release(vfd);
1084unreg_dev:
1085        v4l2_device_unregister(&dev->v4l2_dev);
1086
1087        return ret;
1088}
1089
1090static int m2mtest_remove(struct platform_device *pdev)
1091{
1092        struct m2mtest_dev *dev =
1093                (struct m2mtest_dev *)platform_get_drvdata(pdev);
1094
1095        v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
1096        v4l2_m2m_release(dev->m2m_dev);
1097        del_timer_sync(&dev->timer);
1098        video_unregister_device(dev->vfd);
1099        v4l2_device_unregister(&dev->v4l2_dev);
1100
1101        return 0;
1102}
1103
1104static struct platform_driver m2mtest_pdrv = {
1105        .probe          = m2mtest_probe,
1106        .remove         = m2mtest_remove,
1107        .driver         = {
1108                .name   = MEM2MEM_NAME,
1109                .owner  = THIS_MODULE,
1110        },
1111};
1112
1113static void __exit m2mtest_exit(void)
1114{
1115        platform_driver_unregister(&m2mtest_pdrv);
1116        platform_device_unregister(&m2mtest_pdev);
1117}
1118
1119static int __init m2mtest_init(void)
1120{
1121        int ret;
1122
1123        ret = platform_device_register(&m2mtest_pdev);
1124        if (ret)
1125                return ret;
1126
1127        ret = platform_driver_register(&m2mtest_pdrv);
1128        if (ret)
1129                platform_device_unregister(&m2mtest_pdev);
1130
1131        return 0;
1132}
1133
1134module_init(m2mtest_init);
1135module_exit(m2mtest_exit);
1136
1137