aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPawel Osciak <p.osciak@samsung.com>2010-04-23 04:38:38 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-19 11:58:04 -0400
commit96d8eab5d0a1a9741a4cae1b3c125d75d1aabedf (patch)
tree26379653e6babe8b19ac46d1aa81b88adc584a67 /drivers
parent7f98639def42a676998d734b381af6c0e64d7791 (diff)
V4L/DVB: [v5,2/2] v4l: Add a mem-to-mem videobuf framework test device
This is a virtual device driver for testing the memory-to-memory framework. This virtual device uses in-memory buffers for both its source and destination. It is capable of multi-instance, multi-buffer-per-transaction operation (via the mem2mem framework). [mchehab@redhat.com: use videobuf_queue_to_vaddr instead of the removed videobuf_queue_to_vmalloc] Signed-off-by: Pawel Osciak <p.osciak@samsung.com> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Vaibhav Hiremath <hvaibhav@ti.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/Kconfig14
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/mem2mem_testdev.c1049
3 files changed, 1064 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index f8cbd4adebfd..16decdd6e28c 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1135,3 +1135,17 @@ menuconfig V4L_MEM2MEM_DRIVERS
1135 use system memory for both source and destination buffers, as opposed 1135 use system memory for both source and destination buffers, as opposed
1136 to capture and output drivers, which use memory buffers for just 1136 to capture and output drivers, which use memory buffers for just
1137 one of those. 1137 one of those.
1138
1139if V4L_MEM2MEM_DRIVERS
1140
1141config VIDEO_MEM2MEM_TESTDEV
1142 tristate "Virtual test device for mem2mem framework"
1143 depends on VIDEO_DEV && VIDEO_V4L2
1144 select VIDEOBUF_VMALLOC
1145 select V4L2_MEM2MEM_DEV
1146 default n
1147 ---help---
1148 This is a virtual test device for the memory-to-memory driver
1149 framework.
1150
1151endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index b57be2f542e8..a688a0f43879 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -151,6 +151,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv/
151obj-$(CONFIG_VIDEO_CX18) += cx18/ 151obj-$(CONFIG_VIDEO_CX18) += cx18/
152 152
153obj-$(CONFIG_VIDEO_VIVI) += vivi.o 153obj-$(CONFIG_VIDEO_VIVI) += vivi.o
154obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
154obj-$(CONFIG_VIDEO_CX23885) += cx23885/ 155obj-$(CONFIG_VIDEO_CX23885) += cx23885/
155 156
156obj-$(CONFIG_VIDEO_AK881X) += ak881x.o 157obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
new file mode 100644
index 000000000000..baf211b9f6ce
--- /dev/null
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -0,0 +1,1049 @@
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, <p.osciak@samsung.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/version.h>
23#include <linux/timer.h>
24#include <linux/sched.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/videobuf-vmalloc.h>
31
32#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev"
33
34MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
35MODULE_AUTHOR("Pawel Osciak, <p.osciak@samsung.com>");
36MODULE_LICENSE("GPL");
37
38
39#define MIN_W 32
40#define MIN_H 32
41#define MAX_W 640
42#define MAX_H 480
43#define DIM_ALIGN_MASK 0x08 /* 8-alignment for dimensions */
44
45/* Flags that indicate a format can be used for capture/output */
46#define MEM2MEM_CAPTURE (1 << 0)
47#define MEM2MEM_OUTPUT (1 << 1)
48
49#define MEM2MEM_NAME "m2m-testdev"
50
51/* Per queue */
52#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME
53/* In bytes, per queue */
54#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024)
55
56/* Default transaction time in msec */
57#define MEM2MEM_DEF_TRANSTIME 1000
58/* Default number of buffers per transaction */
59#define MEM2MEM_DEF_TRANSLEN 1
60#define MEM2MEM_COLOR_STEP (0xff >> 4)
61#define MEM2MEM_NUM_TILES 8
62
63#define dprintk(dev, fmt, arg...) \
64 v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
65
66
67void m2mtest_dev_release(struct device *dev)
68{}
69
70static struct platform_device m2mtest_pdev = {
71 .name = MEM2MEM_NAME,
72 .dev.release = m2mtest_dev_release,
73};
74
75struct m2mtest_fmt {
76 char *name;
77 u32 fourcc;
78 int depth;
79 /* Types the format can be used for */
80 u32 types;
81};
82
83static struct m2mtest_fmt formats[] = {
84 {
85 .name = "RGB565 (BE)",
86 .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
87 .depth = 16,
88 /* Both capture and output format */
89 .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
90 },
91 {
92 .name = "4:2:2, packed, YUYV",
93 .fourcc = V4L2_PIX_FMT_YUYV,
94 .depth = 16,
95 /* Output-only format */
96 .types = MEM2MEM_OUTPUT,
97 },
98};
99
100/* Per-queue, driver-specific private data */
101struct m2mtest_q_data {
102 unsigned int width;
103 unsigned int height;
104 unsigned int sizeimage;
105 struct m2mtest_fmt *fmt;
106};
107
108enum {
109 V4L2_M2M_SRC = 0,
110 V4L2_M2M_DST = 1,
111};
112
113/* Source and destination queue data */
114static struct m2mtest_q_data q_data[2];
115
116static struct m2mtest_q_data *get_q_data(enum v4l2_buf_type type)
117{
118 switch (type) {
119 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
120 return &q_data[V4L2_M2M_SRC];
121 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
122 return &q_data[V4L2_M2M_DST];
123 default:
124 BUG();
125 }
126 return NULL;
127}
128
129#define V4L2_CID_TRANS_TIME_MSEC V4L2_CID_PRIVATE_BASE
130#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_PRIVATE_BASE + 1)
131
132static struct v4l2_queryctrl m2mtest_ctrls[] = {
133 {
134 .id = V4L2_CID_TRANS_TIME_MSEC,
135 .type = V4L2_CTRL_TYPE_INTEGER,
136 .name = "Transaction time (msec)",
137 .minimum = 1,
138 .maximum = 10000,
139 .step = 100,
140 .default_value = 1000,
141 .flags = 0,
142 }, {
143 .id = V4L2_CID_TRANS_NUM_BUFS,
144 .type = V4L2_CTRL_TYPE_INTEGER,
145 .name = "Buffers per transaction",
146 .minimum = 1,
147 .maximum = MEM2MEM_DEF_NUM_BUFS,
148 .step = 1,
149 .default_value = 1,
150 .flags = 0,
151 },
152};
153
154#define NUM_FORMATS ARRAY_SIZE(formats)
155
156static struct m2mtest_fmt *find_format(struct v4l2_format *f)
157{
158 struct m2mtest_fmt *fmt;
159 unsigned int k;
160
161 for (k = 0; k < NUM_FORMATS; k++) {
162 fmt = &formats[k];
163 if (fmt->fourcc == f->fmt.pix.pixelformat)
164 break;
165 }
166
167 if (k == NUM_FORMATS)
168 return NULL;
169
170 return &formats[k];
171}
172
173struct m2mtest_dev {
174 struct v4l2_device v4l2_dev;
175 struct video_device *vfd;
176
177 atomic_t num_inst;
178 struct mutex dev_mutex;
179 spinlock_t irqlock;
180
181 struct timer_list timer;
182
183 struct v4l2_m2m_dev *m2m_dev;
184};
185
186struct m2mtest_ctx {
187 struct m2mtest_dev *dev;
188
189 /* Processed buffers in this transaction */
190 u8 num_processed;
191
192 /* Transaction length (i.e. how many buffers per transaction) */
193 u32 translen;
194 /* Transaction time (i.e. simulated processing time) in milliseconds */
195 u32 transtime;
196
197 /* Abort requested by m2m */
198 int aborting;
199
200 struct v4l2_m2m_ctx *m2m_ctx;
201};
202
203struct m2mtest_buffer {
204 /* vb must be first! */
205 struct videobuf_buffer vb;
206};
207
208static struct v4l2_queryctrl *get_ctrl(int id)
209{
210 int i;
211
212 for (i = 0; i < ARRAY_SIZE(m2mtest_ctrls); ++i) {
213 if (id == m2mtest_ctrls[i].id)
214 return &m2mtest_ctrls[i];
215 }
216
217 return NULL;
218}
219
220static int device_process(struct m2mtest_ctx *ctx,
221 struct m2mtest_buffer *in_buf,
222 struct m2mtest_buffer *out_buf)
223{
224 struct m2mtest_dev *dev = ctx->dev;
225 u8 *p_in, *p_out;
226 int x, y, t, w;
227 int tile_w, bytes_left;
228 struct videobuf_queue *src_q;
229 struct videobuf_queue *dst_q;
230
231 src_q = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
232 dst_q = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
233 p_in = videobuf_queue_to_vaddr(src_q, &in_buf->vb);
234 p_out = videobuf_queue_to_vaddr(dst_q, &out_buf->vb);
235 if (!p_in || !p_out) {
236 v4l2_err(&dev->v4l2_dev,
237 "Acquiring kernel pointers to buffers failed\n");
238 return -EFAULT;
239 }
240
241 if (in_buf->vb.size < out_buf->vb.size) {
242 v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
243 return -EINVAL;
244 }
245
246 tile_w = (in_buf->vb.width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
247 / MEM2MEM_NUM_TILES;
248 bytes_left = in_buf->vb.bytesperline - tile_w * MEM2MEM_NUM_TILES;
249 w = 0;
250
251 for (y = 0; y < in_buf->vb.height; ++y) {
252 for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
253 if (w & 0x1) {
254 for (x = 0; x < tile_w; ++x)
255 *p_out++ = *p_in++ + MEM2MEM_COLOR_STEP;
256 } else {
257 for (x = 0; x < tile_w; ++x)
258 *p_out++ = *p_in++ - MEM2MEM_COLOR_STEP;
259 }
260 ++w;
261 }
262 p_in += bytes_left;
263 p_out += bytes_left;
264 }
265
266 return 0;
267}
268
269static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout)
270{
271 dprintk(dev, "Scheduling a simulated irq\n");
272 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
273}
274
275/*
276 * mem2mem callbacks
277 */
278
279/**
280 * job_ready() - check whether an instance is ready to be scheduled to run
281 */
282static int job_ready(void *priv)
283{
284 struct m2mtest_ctx *ctx = priv;
285
286 if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen
287 || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) {
288 dprintk(ctx->dev, "Not enough buffers available\n");
289 return 0;
290 }
291
292 return 1;
293}
294
295static void job_abort(void *priv)
296{
297 struct m2mtest_ctx *ctx = priv;
298
299 /* Will cancel the transaction in the next interrupt handler */
300 ctx->aborting = 1;
301}
302
303/* device_run() - prepares and starts the device
304 *
305 * This simulates all the immediate preparations required before starting
306 * a device. This will be called by the framework when it decides to schedule
307 * a particular instance.
308 */
309static void device_run(void *priv)
310{
311 struct m2mtest_ctx *ctx = priv;
312 struct m2mtest_dev *dev = ctx->dev;
313 struct m2mtest_buffer *src_buf, *dst_buf;
314
315 src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
316 dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
317
318 device_process(ctx, src_buf, dst_buf);
319
320 /* Run a timer, which simulates a hardware irq */
321 schedule_irq(dev, ctx->transtime);
322}
323
324
325static void device_isr(unsigned long priv)
326{
327 struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv;
328 struct m2mtest_ctx *curr_ctx;
329 struct m2mtest_buffer *src_buf, *dst_buf;
330 unsigned long flags;
331
332 curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev);
333
334 if (NULL == curr_ctx) {
335 printk(KERN_ERR
336 "Instance released before the end of transaction\n");
337 return;
338 }
339
340 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
341 dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
342 curr_ctx->num_processed++;
343
344 if (curr_ctx->num_processed == curr_ctx->translen
345 || curr_ctx->aborting) {
346 dprintk(curr_ctx->dev, "Finishing transaction\n");
347 curr_ctx->num_processed = 0;
348 spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
349 src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
350 wake_up(&src_buf->vb.done);
351 wake_up(&dst_buf->vb.done);
352 spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
353 v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
354 } else {
355 spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
356 src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
357 wake_up(&src_buf->vb.done);
358 wake_up(&dst_buf->vb.done);
359 spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
360 device_run(curr_ctx);
361 }
362}
363
364
365/*
366 * video ioctls
367 */
368static int vidioc_querycap(struct file *file, void *priv,
369 struct v4l2_capability *cap)
370{
371 strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
372 strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
373 cap->bus_info[0] = 0;
374 cap->version = KERNEL_VERSION(0, 1, 0);
375 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
376 | V4L2_CAP_STREAMING;
377
378 return 0;
379}
380
381static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
382{
383 int i, num;
384 struct m2mtest_fmt *fmt;
385
386 num = 0;
387
388 for (i = 0; i < NUM_FORMATS; ++i) {
389 if (formats[i].types & type) {
390 /* index-th format of type type found ? */
391 if (num == f->index)
392 break;
393 /* Correct type but haven't reached our index yet,
394 * just increment per-type index */
395 ++num;
396 }
397 }
398
399 if (i < NUM_FORMATS) {
400 /* Format found */
401 fmt = &formats[i];
402 strncpy(f->description, fmt->name, sizeof(f->description) - 1);
403 f->pixelformat = fmt->fourcc;
404 return 0;
405 }
406
407 /* Format not found */
408 return -EINVAL;
409}
410
411static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
412 struct v4l2_fmtdesc *f)
413{
414 return enum_fmt(f, MEM2MEM_CAPTURE);
415}
416
417static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
418 struct v4l2_fmtdesc *f)
419{
420 return enum_fmt(f, MEM2MEM_OUTPUT);
421}
422
423static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
424{
425 struct videobuf_queue *vq;
426 struct m2mtest_q_data *q_data;
427
428 vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
429 if (!vq)
430 return -EINVAL;
431
432 q_data = get_q_data(f->type);
433
434 f->fmt.pix.width = q_data->width;
435 f->fmt.pix.height = q_data->height;
436 f->fmt.pix.field = vq->field;
437 f->fmt.pix.pixelformat = q_data->fmt->fourcc;
438 f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
439 f->fmt.pix.sizeimage = q_data->sizeimage;
440
441 return 0;
442}
443
444static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
445 struct v4l2_format *f)
446{
447 return vidioc_g_fmt(priv, f);
448}
449
450static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
451 struct v4l2_format *f)
452{
453 return vidioc_g_fmt(priv, f);
454}
455
456static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
457{
458 enum v4l2_field field;
459
460 field = f->fmt.pix.field;
461
462 if (field == V4L2_FIELD_ANY)
463 field = V4L2_FIELD_NONE;
464 else if (V4L2_FIELD_NONE != field)
465 return -EINVAL;
466
467 /* V4L2 specification suggests the driver corrects the format struct
468 * if any of the dimensions is unsupported */
469 f->fmt.pix.field = field;
470
471 if (f->fmt.pix.height < MIN_H)
472 f->fmt.pix.height = MIN_H;
473 else if (f->fmt.pix.height > MAX_H)
474 f->fmt.pix.height = MAX_H;
475
476 if (f->fmt.pix.width < MIN_W)
477 f->fmt.pix.width = MIN_W;
478 else if (f->fmt.pix.width > MAX_W)
479 f->fmt.pix.width = MAX_W;
480
481 f->fmt.pix.width &= ~DIM_ALIGN_MASK;
482 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
483 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
484
485 return 0;
486}
487
488static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
489 struct v4l2_format *f)
490{
491 struct m2mtest_fmt *fmt;
492 struct m2mtest_ctx *ctx = priv;
493
494 fmt = find_format(f);
495 if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
496 v4l2_err(&ctx->dev->v4l2_dev,
497 "Fourcc format (0x%08x) invalid.\n",
498 f->fmt.pix.pixelformat);
499 return -EINVAL;
500 }
501
502 return vidioc_try_fmt(f, fmt);
503}
504
505static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
506 struct v4l2_format *f)
507{
508 struct m2mtest_fmt *fmt;
509 struct m2mtest_ctx *ctx = priv;
510
511 fmt = find_format(f);
512 if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
513 v4l2_err(&ctx->dev->v4l2_dev,
514 "Fourcc format (0x%08x) invalid.\n",
515 f->fmt.pix.pixelformat);
516 return -EINVAL;
517 }
518
519 return vidioc_try_fmt(f, fmt);
520}
521
522static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
523{
524 struct m2mtest_q_data *q_data;
525 struct videobuf_queue *vq;
526 int ret = 0;
527
528 vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
529 if (!vq)
530 return -EINVAL;
531
532 q_data = get_q_data(f->type);
533 if (!q_data)
534 return -EINVAL;
535
536 mutex_lock(&vq->vb_lock);
537
538 if (videobuf_queue_is_busy(vq)) {
539 v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
540 ret = -EBUSY;
541 goto out;
542 }
543
544 q_data->fmt = find_format(f);
545 q_data->width = f->fmt.pix.width;
546 q_data->height = f->fmt.pix.height;
547 q_data->sizeimage = q_data->width * q_data->height
548 * q_data->fmt->depth >> 3;
549 vq->field = f->fmt.pix.field;
550
551 dprintk(ctx->dev,
552 "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
553 f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
554
555out:
556 mutex_unlock(&vq->vb_lock);
557 return ret;
558}
559
560static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
561 struct v4l2_format *f)
562{
563 int ret;
564
565 ret = vidioc_try_fmt_vid_cap(file, priv, f);
566 if (ret)
567 return ret;
568
569 return vidioc_s_fmt(priv, f);
570}
571
572static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
573 struct v4l2_format *f)
574{
575 int ret;
576
577 ret = vidioc_try_fmt_vid_out(file, priv, f);
578 if (ret)
579 return ret;
580
581 return vidioc_s_fmt(priv, f);
582}
583
584static int vidioc_reqbufs(struct file *file, void *priv,
585 struct v4l2_requestbuffers *reqbufs)
586{
587 struct m2mtest_ctx *ctx = priv;
588
589 return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
590}
591
592static int vidioc_querybuf(struct file *file, void *priv,
593 struct v4l2_buffer *buf)
594{
595 struct m2mtest_ctx *ctx = priv;
596
597 return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
598}
599
600static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
601{
602 struct m2mtest_ctx *ctx = priv;
603
604 return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
605}
606
607static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
608{
609 struct m2mtest_ctx *ctx = priv;
610
611 return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
612}
613
614static int vidioc_streamon(struct file *file, void *priv,
615 enum v4l2_buf_type type)
616{
617 struct m2mtest_ctx *ctx = priv;
618
619 return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
620}
621
622static int vidioc_streamoff(struct file *file, void *priv,
623 enum v4l2_buf_type type)
624{
625 struct m2mtest_ctx *ctx = priv;
626
627 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
628}
629
630static int vidioc_queryctrl(struct file *file, void *priv,
631 struct v4l2_queryctrl *qc)
632{
633 struct v4l2_queryctrl *c;
634
635 c = get_ctrl(qc->id);
636 if (!c)
637 return -EINVAL;
638
639 *qc = *c;
640 return 0;
641}
642
643static int vidioc_g_ctrl(struct file *file, void *priv,
644 struct v4l2_control *ctrl)
645{
646 struct m2mtest_ctx *ctx = priv;
647
648 switch (ctrl->id) {
649 case V4L2_CID_TRANS_TIME_MSEC:
650 ctrl->value = ctx->transtime;
651 break;
652
653 case V4L2_CID_TRANS_NUM_BUFS:
654 ctrl->value = ctx->translen;
655 break;
656
657 default:
658 v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
659 return -EINVAL;
660 }
661
662 return 0;
663}
664
665static int check_ctrl_val(struct m2mtest_ctx *ctx, struct v4l2_control *ctrl)
666{
667 struct v4l2_queryctrl *c;
668
669 c = get_ctrl(ctrl->id);
670 if (!c)
671 return -EINVAL;
672
673 if (ctrl->value < c->minimum || ctrl->value > c->maximum) {
674 v4l2_err(&ctx->dev->v4l2_dev, "Value out of range\n");
675 return -ERANGE;
676 }
677
678 return 0;
679}
680
681static int vidioc_s_ctrl(struct file *file, void *priv,
682 struct v4l2_control *ctrl)
683{
684 struct m2mtest_ctx *ctx = priv;
685 int ret = 0;
686
687 ret = check_ctrl_val(ctx, ctrl);
688 if (ret != 0)
689 return ret;
690
691 switch (ctrl->id) {
692 case V4L2_CID_TRANS_TIME_MSEC:
693 ctx->transtime = ctrl->value;
694 break;
695
696 case V4L2_CID_TRANS_NUM_BUFS:
697 ctx->translen = ctrl->value;
698 break;
699
700 default:
701 v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
702 return -EINVAL;
703 }
704
705 return 0;
706}
707
708
709static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
710 .vidioc_querycap = vidioc_querycap,
711
712 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
713 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
714 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
715 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
716
717 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
718 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
719 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
720 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
721
722 .vidioc_reqbufs = vidioc_reqbufs,
723 .vidioc_querybuf = vidioc_querybuf,
724
725 .vidioc_qbuf = vidioc_qbuf,
726 .vidioc_dqbuf = vidioc_dqbuf,
727
728 .vidioc_streamon = vidioc_streamon,
729 .vidioc_streamoff = vidioc_streamoff,
730
731 .vidioc_queryctrl = vidioc_queryctrl,
732 .vidioc_g_ctrl = vidioc_g_ctrl,
733 .vidioc_s_ctrl = vidioc_s_ctrl,
734};
735
736
737/*
738 * Queue operations
739 */
740
741static void m2mtest_buf_release(struct videobuf_queue *vq,
742 struct videobuf_buffer *vb)
743{
744 struct m2mtest_ctx *ctx = vq->priv_data;
745
746 dprintk(ctx->dev, "type: %d, index: %d, state: %d\n",
747 vq->type, vb->i, vb->state);
748
749 videobuf_vmalloc_free(vb);
750 vb->state = VIDEOBUF_NEEDS_INIT;
751}
752
753static int m2mtest_buf_setup(struct videobuf_queue *vq, unsigned int *count,
754 unsigned int *size)
755{
756 struct m2mtest_ctx *ctx = vq->priv_data;
757 struct m2mtest_q_data *q_data;
758
759 q_data = get_q_data(vq->type);
760
761 *size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
762 dprintk(ctx->dev, "size:%d, w/h %d/%d, depth: %d\n",
763 *size, q_data->width, q_data->height, q_data->fmt->depth);
764
765 if (0 == *count)
766 *count = MEM2MEM_DEF_NUM_BUFS;
767
768 while (*size * *count > MEM2MEM_VID_MEM_LIMIT)
769 (*count)--;
770
771 v4l2_info(&ctx->dev->v4l2_dev,
772 "%d buffers of size %d set up.\n", *count, *size);
773
774 return 0;
775}
776
777static int m2mtest_buf_prepare(struct videobuf_queue *vq,
778 struct videobuf_buffer *vb,
779 enum v4l2_field field)
780{
781 struct m2mtest_ctx *ctx = vq->priv_data;
782 struct m2mtest_q_data *q_data;
783 int ret;
784
785 dprintk(ctx->dev, "type: %d, index: %d, state: %d\n",
786 vq->type, vb->i, vb->state);
787
788 q_data = get_q_data(vq->type);
789
790 if (vb->baddr) {
791 /* User-provided buffer */
792 if (vb->bsize < q_data->sizeimage) {
793 /* Buffer too small to fit a frame */
794 v4l2_err(&ctx->dev->v4l2_dev,
795 "User-provided buffer too small\n");
796 return -EINVAL;
797 }
798 } else if (vb->state != VIDEOBUF_NEEDS_INIT
799 && vb->bsize < q_data->sizeimage) {
800 /* We provide the buffer, but it's already been initialized
801 * and is too small */
802 return -EINVAL;
803 }
804
805 vb->width = q_data->width;
806 vb->height = q_data->height;
807 vb->bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
808 vb->size = q_data->sizeimage;
809 vb->field = field;
810
811 if (VIDEOBUF_NEEDS_INIT == vb->state) {
812 ret = videobuf_iolock(vq, vb, NULL);
813 if (ret) {
814 v4l2_err(&ctx->dev->v4l2_dev,
815 "Iolock failed\n");
816 goto fail;
817 }
818 }
819
820 vb->state = VIDEOBUF_PREPARED;
821
822 return 0;
823fail:
824 m2mtest_buf_release(vq, vb);
825 return ret;
826}
827
828static void m2mtest_buf_queue(struct videobuf_queue *vq,
829 struct videobuf_buffer *vb)
830{
831 struct m2mtest_ctx *ctx = vq->priv_data;
832
833 v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
834}
835
836static struct videobuf_queue_ops m2mtest_qops = {
837 .buf_setup = m2mtest_buf_setup,
838 .buf_prepare = m2mtest_buf_prepare,
839 .buf_queue = m2mtest_buf_queue,
840 .buf_release = m2mtest_buf_release,
841};
842
843static void queue_init(void *priv, struct videobuf_queue *vq,
844 enum v4l2_buf_type type)
845{
846 struct m2mtest_ctx *ctx = priv;
847
848 videobuf_queue_vmalloc_init(vq, &m2mtest_qops, ctx->dev->v4l2_dev.dev,
849 &ctx->dev->irqlock, type, V4L2_FIELD_NONE,
850 sizeof(struct m2mtest_buffer), priv);
851}
852
853
854/*
855 * File operations
856 */
857static int m2mtest_open(struct file *file)
858{
859 struct m2mtest_dev *dev = video_drvdata(file);
860 struct m2mtest_ctx *ctx = NULL;
861
862 ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
863 if (!ctx)
864 return -ENOMEM;
865
866 file->private_data = ctx;
867 ctx->dev = dev;
868 ctx->translen = MEM2MEM_DEF_TRANSLEN;
869 ctx->transtime = MEM2MEM_DEF_TRANSTIME;
870 ctx->num_processed = 0;
871
872 ctx->m2m_ctx = v4l2_m2m_ctx_init(ctx, dev->m2m_dev, queue_init);
873 if (IS_ERR(ctx->m2m_ctx)) {
874 kfree(ctx);
875 return PTR_ERR(ctx->m2m_ctx);
876 }
877
878 atomic_inc(&dev->num_inst);
879
880 dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
881
882 return 0;
883}
884
885static int m2mtest_release(struct file *file)
886{
887 struct m2mtest_dev *dev = video_drvdata(file);
888 struct m2mtest_ctx *ctx = file->private_data;
889
890 dprintk(dev, "Releasing instance %p\n", ctx);
891
892 v4l2_m2m_ctx_release(ctx->m2m_ctx);
893 kfree(ctx);
894
895 atomic_dec(&dev->num_inst);
896
897 return 0;
898}
899
900static unsigned int m2mtest_poll(struct file *file,
901 struct poll_table_struct *wait)
902{
903 struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
904
905 return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
906}
907
908static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
909{
910 struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
911
912 return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
913}
914
915static const struct v4l2_file_operations m2mtest_fops = {
916 .owner = THIS_MODULE,
917 .open = m2mtest_open,
918 .release = m2mtest_release,
919 .poll = m2mtest_poll,
920 .ioctl = video_ioctl2,
921 .mmap = m2mtest_mmap,
922};
923
924static struct video_device m2mtest_videodev = {
925 .name = MEM2MEM_NAME,
926 .fops = &m2mtest_fops,
927 .ioctl_ops = &m2mtest_ioctl_ops,
928 .minor = -1,
929 .release = video_device_release,
930};
931
932static struct v4l2_m2m_ops m2m_ops = {
933 .device_run = device_run,
934 .job_ready = job_ready,
935 .job_abort = job_abort,
936};
937
938static int m2mtest_probe(struct platform_device *pdev)
939{
940 struct m2mtest_dev *dev;
941 struct video_device *vfd;
942 int ret;
943
944 dev = kzalloc(sizeof *dev, GFP_KERNEL);
945 if (!dev)
946 return -ENOMEM;
947
948 spin_lock_init(&dev->irqlock);
949
950 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
951 if (ret)
952 goto free_dev;
953
954 atomic_set(&dev->num_inst, 0);
955 mutex_init(&dev->dev_mutex);
956
957 vfd = video_device_alloc();
958 if (!vfd) {
959 v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
960 ret = -ENOMEM;
961 goto unreg_dev;
962 }
963
964 *vfd = m2mtest_videodev;
965
966 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
967 if (ret) {
968 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
969 goto rel_vdev;
970 }
971
972 video_set_drvdata(vfd, dev);
973 snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name);
974 dev->vfd = vfd;
975 v4l2_info(&dev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
976 "Device registered as /dev/video%d\n", vfd->num);
977
978 setup_timer(&dev->timer, device_isr, (long)dev);
979 platform_set_drvdata(pdev, dev);
980
981 dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
982 if (IS_ERR(dev->m2m_dev)) {
983 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
984 ret = PTR_ERR(dev->m2m_dev);
985 goto err_m2m;
986 }
987
988 return 0;
989
990err_m2m:
991 video_unregister_device(dev->vfd);
992rel_vdev:
993 video_device_release(vfd);
994unreg_dev:
995 v4l2_device_unregister(&dev->v4l2_dev);
996free_dev:
997 kfree(dev);
998
999 return ret;
1000}
1001
1002static int m2mtest_remove(struct platform_device *pdev)
1003{
1004 struct m2mtest_dev *dev =
1005 (struct m2mtest_dev *)platform_get_drvdata(pdev);
1006
1007 v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
1008 v4l2_m2m_release(dev->m2m_dev);
1009 del_timer_sync(&dev->timer);
1010 video_unregister_device(dev->vfd);
1011 v4l2_device_unregister(&dev->v4l2_dev);
1012 kfree(dev);
1013
1014 return 0;
1015}
1016
1017static struct platform_driver m2mtest_pdrv = {
1018 .probe = m2mtest_probe,
1019 .remove = m2mtest_remove,
1020 .driver = {
1021 .name = MEM2MEM_NAME,
1022 .owner = THIS_MODULE,
1023 },
1024};
1025
1026static void __exit m2mtest_exit(void)
1027{
1028 platform_driver_unregister(&m2mtest_pdrv);
1029 platform_device_unregister(&m2mtest_pdev);
1030}
1031
1032static int __init m2mtest_init(void)
1033{
1034 int ret;
1035
1036 ret = platform_device_register(&m2mtest_pdev);
1037 if (ret)
1038 return ret;
1039
1040 ret = platform_driver_register(&m2mtest_pdrv);
1041 if (ret)
1042 platform_device_unregister(&m2mtest_pdev);
1043
1044 return 0;
1045}
1046
1047module_init(m2mtest_init);
1048module_exit(m2mtest_exit);
1049