1 // SPDX-License-Identifier: GPL-2.0+
3 * A virtual v4l2-mem2mem example device.
5 * This is a virtual device driver for testing mem-to-mem videobuf framework.
6 * It simulates a device that uses memory buffers for both source and
7 * destination, processes the data and issues an "irq" (simulated by a delayed
9 * The device is capable of multi-instance, multi-buffer-per-transaction
10 * operation (via the mem2mem framework).
12 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
13 * Pawel Osciak, <pawel@osciak.com>
14 * Marek Szyprowski, <m.szyprowski@samsung.com>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by the
18 * Free Software Foundation; either version 2 of the
19 * License, or (at your option) any later version
21 #include <linux/module.h>
22 #include <linux/delay.h>
24 #include <linux/sched.h>
25 #include <linux/slab.h>
27 #include <linux/platform_device.h>
28 #include <media/v4l2-mem2mem.h>
29 #include <media/v4l2-device.h>
30 #include <media/v4l2-ioctl.h>
31 #include <media/v4l2-ctrls.h>
32 #include <media/v4l2-event.h>
33 #include <media/videobuf2-vmalloc.h>
35 MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
36 MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
37 MODULE_LICENSE("GPL");
38 MODULE_VERSION("0.2");
39 MODULE_ALIAS("mem2mem_testdev");
41 static unsigned int debug
;
42 module_param(debug
, uint
, 0644);
43 MODULE_PARM_DESC(debug
, "debug level");
45 /* Default transaction time in msec */
46 static unsigned int default_transtime
= 40; /* Max 25 fps */
47 module_param(default_transtime
, uint
, 0644);
48 MODULE_PARM_DESC(default_transtime
, "default transaction time in ms");
55 /* Pixel alignment for non-bayer formats */
57 #define HEIGHT_ALIGN 1
59 /* Pixel alignment for bayer formats */
60 #define BAYER_WIDTH_ALIGN 2
61 #define BAYER_HEIGHT_ALIGN 2
63 /* Flags that indicate a format can be used for capture/output */
64 #define MEM2MEM_CAPTURE BIT(0)
65 #define MEM2MEM_OUTPUT BIT(1)
67 #define MEM2MEM_NAME "vim2m"
70 #define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME
71 /* In bytes, per queue */
72 #define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024)
74 /* Flags that indicate processing mode */
75 #define MEM2MEM_HFLIP BIT(0)
76 #define MEM2MEM_VFLIP BIT(1)
78 #define dprintk(dev, lvl, fmt, arg...) \
79 v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg)
81 static void vim2m_dev_release(struct device
*dev
)
84 static struct platform_device vim2m_pdev
= {
86 .dev
.release
= vim2m_dev_release
,
92 /* Types the format can be used for */
96 static struct vim2m_fmt formats
[] = {
98 .fourcc
= V4L2_PIX_FMT_RGB565
, /* rrrrrggg gggbbbbb */
100 .types
= MEM2MEM_CAPTURE
| MEM2MEM_OUTPUT
,
102 .fourcc
= V4L2_PIX_FMT_RGB565X
, /* gggbbbbb rrrrrggg */
104 .types
= MEM2MEM_CAPTURE
| MEM2MEM_OUTPUT
,
106 .fourcc
= V4L2_PIX_FMT_RGB24
,
108 .types
= MEM2MEM_CAPTURE
| MEM2MEM_OUTPUT
,
110 .fourcc
= V4L2_PIX_FMT_BGR24
,
112 .types
= MEM2MEM_CAPTURE
| MEM2MEM_OUTPUT
,
114 .fourcc
= V4L2_PIX_FMT_YUYV
,
116 .types
= MEM2MEM_CAPTURE
,
118 .fourcc
= V4L2_PIX_FMT_SBGGR8
,
120 .types
= MEM2MEM_CAPTURE
,
122 .fourcc
= V4L2_PIX_FMT_SGBRG8
,
124 .types
= MEM2MEM_CAPTURE
,
126 .fourcc
= V4L2_PIX_FMT_SGRBG8
,
128 .types
= MEM2MEM_CAPTURE
,
130 .fourcc
= V4L2_PIX_FMT_SRGGB8
,
132 .types
= MEM2MEM_CAPTURE
,
136 #define NUM_FORMATS ARRAY_SIZE(formats)
138 /* Per-queue, driver-specific private data */
139 struct vim2m_q_data
{
142 unsigned int sizeimage
;
143 unsigned int sequence
;
144 struct vim2m_fmt
*fmt
;
152 #define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000)
153 #define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001)
155 static struct vim2m_fmt
*find_format(u32 fourcc
)
157 struct vim2m_fmt
*fmt
;
160 for (k
= 0; k
< NUM_FORMATS
; k
++) {
162 if (fmt
->fourcc
== fourcc
)
166 if (k
== NUM_FORMATS
)
172 static void get_alignment(u32 fourcc
,
173 unsigned int *walign
, unsigned int *halign
)
176 case V4L2_PIX_FMT_SBGGR8
:
177 case V4L2_PIX_FMT_SGBRG8
:
178 case V4L2_PIX_FMT_SGRBG8
:
179 case V4L2_PIX_FMT_SRGGB8
:
180 *walign
= BAYER_WIDTH_ALIGN
;
181 *halign
= BAYER_HEIGHT_ALIGN
;
184 *walign
= WIDTH_ALIGN
;
185 *halign
= HEIGHT_ALIGN
;
191 struct v4l2_device v4l2_dev
;
192 struct video_device vfd
;
193 #ifdef CONFIG_MEDIA_CONTROLLER
194 struct media_device mdev
;
198 struct mutex dev_mutex
;
200 struct v4l2_m2m_dev
*m2m_dev
;
205 struct vim2m_dev
*dev
;
207 struct v4l2_ctrl_handler hdl
;
209 /* Processed buffers in this transaction */
212 /* Transaction length (i.e. how many buffers per transaction) */
214 /* Transaction time (i.e. simulated processing time) in milliseconds */
217 struct mutex vb_mutex
;
218 struct delayed_work work_run
;
220 /* Abort requested by m2m */
223 /* Processing mode */
226 enum v4l2_colorspace colorspace
;
227 enum v4l2_ycbcr_encoding ycbcr_enc
;
228 enum v4l2_xfer_func xfer_func
;
229 enum v4l2_quantization quant
;
231 /* Source and destination queue data */
232 struct vim2m_q_data q_data
[2];
235 static inline struct vim2m_ctx
*file2ctx(struct file
*file
)
237 return container_of(file
->private_data
, struct vim2m_ctx
, fh
);
240 static struct vim2m_q_data
*get_q_data(struct vim2m_ctx
*ctx
,
241 enum v4l2_buf_type type
)
244 case V4L2_BUF_TYPE_VIDEO_OUTPUT
:
245 return &ctx
->q_data
[V4L2_M2M_SRC
];
246 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
247 return &ctx
->q_data
[V4L2_M2M_DST
];
253 static const char *type_name(enum v4l2_buf_type type
)
256 case V4L2_BUF_TYPE_VIDEO_OUTPUT
:
258 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
265 #define CLIP(__color) \
266 (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color)))
268 static void copy_line(struct vim2m_q_data
*q_data_out
,
269 u8
*src
, u8
*dst
, bool reverse
)
271 int x
, depth
= q_data_out
->fmt
->depth
>> 3;
274 memcpy(dst
, src
, q_data_out
->width
* depth
);
276 for (x
= 0; x
< q_data_out
->width
>> 1; x
++) {
277 memcpy(dst
, src
, depth
);
278 memcpy(dst
+ depth
, src
- depth
, depth
);
286 static void copy_two_pixels(struct vim2m_q_data
*q_data_in
,
287 struct vim2m_q_data
*q_data_out
,
288 u8
*src
[2], u8
**dst
, int ypos
, bool reverse
)
290 struct vim2m_fmt
*out
= q_data_out
->fmt
;
291 struct vim2m_fmt
*in
= q_data_in
->fmt
;
292 u8 _r
[2], _g
[2], _b
[2], *r
, *g
, *b
;
295 /* Step 1: read two consecutive pixels from src pointer */
301 switch (in
->fourcc
) {
302 case V4L2_PIX_FMT_RGB565
: /* rrrrrggg gggbbbbb */
303 for (i
= 0; i
< 2; i
++) {
304 u16 pix
= le16_to_cpu(*(__le16
*)(src
[i
]));
306 *r
++ = (u8
)(((pix
& 0xf800) >> 11) << 3) | 0x07;
307 *g
++ = (u8
)((((pix
& 0x07e0) >> 5)) << 2) | 0x03;
308 *b
++ = (u8
)((pix
& 0x1f) << 3) | 0x07;
311 case V4L2_PIX_FMT_RGB565X
: /* gggbbbbb rrrrrggg */
312 for (i
= 0; i
< 2; i
++) {
313 u16 pix
= be16_to_cpu(*(__be16
*)(src
[i
]));
315 *r
++ = (u8
)(((pix
& 0xf800) >> 11) << 3) | 0x07;
316 *g
++ = (u8
)((((pix
& 0x07e0) >> 5)) << 2) | 0x03;
317 *b
++ = (u8
)((pix
& 0x1f) << 3) | 0x07;
321 case V4L2_PIX_FMT_RGB24
:
322 for (i
= 0; i
< 2; i
++) {
328 case V4L2_PIX_FMT_BGR24
:
329 for (i
= 0; i
< 2; i
++) {
337 /* Step 2: store two consecutive points, reversing them if needed */
343 switch (out
->fourcc
) {
344 case V4L2_PIX_FMT_RGB565
: /* rrrrrggg gggbbbbb */
345 for (i
= 0; i
< 2; i
++) {
347 __le16
*dst_pix
= (__le16
*)*dst
;
349 pix
= ((*r
<< 8) & 0xf800) | ((*g
<< 3) & 0x07e0) |
352 *dst_pix
= cpu_to_le16(pix
);
357 case V4L2_PIX_FMT_RGB565X
: /* gggbbbbb rrrrrggg */
358 for (i
= 0; i
< 2; i
++) {
360 __be16
*dst_pix
= (__be16
*)*dst
;
362 pix
= ((*r
<< 8) & 0xf800) | ((*g
<< 3) & 0x07e0) |
365 *dst_pix
= cpu_to_be16(pix
);
370 case V4L2_PIX_FMT_RGB24
:
371 for (i
= 0; i
< 2; i
++) {
377 case V4L2_PIX_FMT_BGR24
:
378 for (i
= 0; i
< 2; i
++) {
384 case V4L2_PIX_FMT_YUYV
:
389 y
= ((8453 * (*r
) + 16594 * (*g
) + 3223 * (*b
)
391 u
= ((-4878 * (*r
) - 9578 * (*g
) + 14456 * (*b
)
393 v
= ((14456 * (*r
++) - 12105 * (*g
++) - 2351 * (*b
++)
395 y1
= ((8453 * (*r
) + 16594 * (*g
) + 3223 * (*b
)
405 case V4L2_PIX_FMT_SBGGR8
:
414 case V4L2_PIX_FMT_SGBRG8
:
423 case V4L2_PIX_FMT_SGRBG8
:
432 case V4L2_PIX_FMT_SRGGB8
:
444 static int device_process(struct vim2m_ctx
*ctx
,
445 struct vb2_v4l2_buffer
*in_vb
,
446 struct vb2_v4l2_buffer
*out_vb
)
448 struct vim2m_dev
*dev
= ctx
->dev
;
449 struct vim2m_q_data
*q_data_in
, *q_data_out
;
450 u8
*p_in
, *p_line
, *p_in_x
[2], *p
, *p_out
;
451 unsigned int width
, height
, bytesperline
, bytes_per_pixel
;
452 unsigned int x
, y
, y_in
, y_out
, x_int
, x_fract
, x_err
, x_offset
;
453 int start
, end
, step
;
455 q_data_in
= get_q_data(ctx
, V4L2_BUF_TYPE_VIDEO_OUTPUT
);
458 bytesperline
= (q_data_in
->width
* q_data_in
->fmt
->depth
) >> 3;
459 bytes_per_pixel
= q_data_in
->fmt
->depth
>> 3;
461 q_data_out
= get_q_data(ctx
, V4L2_BUF_TYPE_VIDEO_CAPTURE
);
465 /* As we're doing scaling, use the output dimensions here */
466 height
= q_data_out
->height
;
467 width
= q_data_out
->width
;
469 p_in
= vb2_plane_vaddr(&in_vb
->vb2_buf
, 0);
470 p_out
= vb2_plane_vaddr(&out_vb
->vb2_buf
, 0);
471 if (!p_in
|| !p_out
) {
472 v4l2_err(&dev
->v4l2_dev
,
473 "Acquiring kernel pointers to buffers failed\n");
477 out_vb
->sequence
= q_data_out
->sequence
++;
478 in_vb
->sequence
= q_data_in
->sequence
++;
479 v4l2_m2m_buf_copy_metadata(in_vb
, out_vb
, true);
481 if (ctx
->mode
& MEM2MEM_VFLIP
) {
493 * When format and resolution are identical,
494 * we can use a faster copy logic
496 if (q_data_in
->fmt
->fourcc
== q_data_out
->fmt
->fourcc
&&
497 q_data_in
->width
== q_data_out
->width
&&
498 q_data_in
->height
== q_data_out
->height
) {
499 for (y
= start
; y
!= end
; y
+= step
, y_out
++) {
500 p
= p_in
+ (y
* bytesperline
);
501 if (ctx
->mode
& MEM2MEM_HFLIP
)
502 p
+= bytesperline
- (q_data_in
->fmt
->depth
>> 3);
504 copy_line(q_data_out
, p
, p_out
,
505 ctx
->mode
& MEM2MEM_HFLIP
);
507 p_out
+= bytesperline
;
512 /* Slower algorithm with format conversion, hflip, vflip and scaler */
514 /* To speed scaler up, use Bresenham for X dimension */
515 x_int
= q_data_in
->width
/ q_data_out
->width
;
516 x_fract
= q_data_in
->width
% q_data_out
->width
;
518 for (y
= start
; y
!= end
; y
+= step
, y_out
++) {
519 y_in
= (y
* q_data_in
->height
) / q_data_out
->height
;
523 p_line
= p_in
+ (y_in
* bytesperline
);
524 if (ctx
->mode
& MEM2MEM_HFLIP
)
525 p_line
+= bytesperline
- (q_data_in
->fmt
->depth
>> 3);
528 for (x
= 0; x
< width
>> 1; x
++) {
536 if (ctx
->mode
& MEM2MEM_HFLIP
)
537 p_in_x
[1] = p_line
- x_offset
* bytes_per_pixel
;
539 p_in_x
[1] = p_line
+ x_offset
* bytes_per_pixel
;
541 copy_two_pixels(q_data_in
, q_data_out
,
542 p_in_x
, &p_out
, y_out
,
543 ctx
->mode
& MEM2MEM_HFLIP
);
545 /* Calculate the next p_in_x0 */
553 if (ctx
->mode
& MEM2MEM_HFLIP
)
554 p_in_x
[0] = p_line
- x_offset
* bytes_per_pixel
;
556 p_in_x
[0] = p_line
+ x_offset
* bytes_per_pixel
;
568 * job_ready() - check whether an instance is ready to be scheduled to run
570 static int job_ready(void *priv
)
572 struct vim2m_ctx
*ctx
= priv
;
574 if (v4l2_m2m_num_src_bufs_ready(ctx
->fh
.m2m_ctx
) < ctx
->translen
575 || v4l2_m2m_num_dst_bufs_ready(ctx
->fh
.m2m_ctx
) < ctx
->translen
) {
576 dprintk(ctx
->dev
, 1, "Not enough buffers available\n");
583 static void job_abort(void *priv
)
585 struct vim2m_ctx
*ctx
= priv
;
587 /* Will cancel the transaction in the next interrupt handler */
591 /* device_run() - prepares and starts the device
593 * This simulates all the immediate preparations required before starting
594 * a device. This will be called by the framework when it decides to schedule
595 * a particular instance.
597 static void device_run(void *priv
)
599 struct vim2m_ctx
*ctx
= priv
;
600 struct vb2_v4l2_buffer
*src_buf
, *dst_buf
;
602 src_buf
= v4l2_m2m_next_src_buf(ctx
->fh
.m2m_ctx
);
603 dst_buf
= v4l2_m2m_next_dst_buf(ctx
->fh
.m2m_ctx
);
605 /* Apply request controls if any */
606 v4l2_ctrl_request_setup(src_buf
->vb2_buf
.req_obj
.req
,
609 device_process(ctx
, src_buf
, dst_buf
);
611 /* Complete request controls if any */
612 v4l2_ctrl_request_complete(src_buf
->vb2_buf
.req_obj
.req
,
615 /* Run delayed work, which simulates a hardware irq */
616 schedule_delayed_work(&ctx
->work_run
, msecs_to_jiffies(ctx
->transtime
));
619 static void device_work(struct work_struct
*w
)
621 struct vim2m_ctx
*curr_ctx
;
622 struct vim2m_dev
*vim2m_dev
;
623 struct vb2_v4l2_buffer
*src_vb
, *dst_vb
;
625 curr_ctx
= container_of(w
, struct vim2m_ctx
, work_run
.work
);
628 pr_err("Instance released before the end of transaction\n");
632 vim2m_dev
= curr_ctx
->dev
;
634 src_vb
= v4l2_m2m_src_buf_remove(curr_ctx
->fh
.m2m_ctx
);
635 dst_vb
= v4l2_m2m_dst_buf_remove(curr_ctx
->fh
.m2m_ctx
);
637 curr_ctx
->num_processed
++;
639 v4l2_m2m_buf_done(src_vb
, VB2_BUF_STATE_DONE
);
640 v4l2_m2m_buf_done(dst_vb
, VB2_BUF_STATE_DONE
);
642 if (curr_ctx
->num_processed
== curr_ctx
->translen
643 || curr_ctx
->aborting
) {
644 dprintk(curr_ctx
->dev
, 2, "Finishing capture buffer fill\n");
645 curr_ctx
->num_processed
= 0;
646 v4l2_m2m_job_finish(vim2m_dev
->m2m_dev
, curr_ctx
->fh
.m2m_ctx
);
648 device_run(curr_ctx
);
655 static int vidioc_querycap(struct file
*file
, void *priv
,
656 struct v4l2_capability
*cap
)
658 strscpy(cap
->driver
, MEM2MEM_NAME
, sizeof(cap
->driver
));
659 strscpy(cap
->card
, MEM2MEM_NAME
, sizeof(cap
->card
));
660 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
),
661 "platform:%s", MEM2MEM_NAME
);
665 static int enum_fmt(struct v4l2_fmtdesc
*f
, u32 type
)
668 struct vim2m_fmt
*fmt
;
672 for (i
= 0; i
< NUM_FORMATS
; ++i
) {
673 if (formats
[i
].types
& type
) {
674 /* index-th format of type type found ? */
678 * Correct type but haven't reached our index yet,
679 * just increment per-type index
685 if (i
< NUM_FORMATS
) {
688 f
->pixelformat
= fmt
->fourcc
;
692 /* Format not found */
696 static int vidioc_enum_fmt_vid_cap(struct file
*file
, void *priv
,
697 struct v4l2_fmtdesc
*f
)
699 return enum_fmt(f
, MEM2MEM_CAPTURE
);
702 static int vidioc_enum_fmt_vid_out(struct file
*file
, void *priv
,
703 struct v4l2_fmtdesc
*f
)
705 return enum_fmt(f
, MEM2MEM_OUTPUT
);
708 static int vidioc_enum_framesizes(struct file
*file
, void *priv
,
709 struct v4l2_frmsizeenum
*fsize
)
711 if (fsize
->index
!= 0)
714 if (!find_format(fsize
->pixel_format
))
717 fsize
->type
= V4L2_FRMSIZE_TYPE_STEPWISE
;
718 fsize
->stepwise
.min_width
= MIN_W
;
719 fsize
->stepwise
.min_height
= MIN_H
;
720 fsize
->stepwise
.max_width
= MAX_W
;
721 fsize
->stepwise
.max_height
= MAX_H
;
723 get_alignment(fsize
->pixel_format
,
724 &fsize
->stepwise
.step_width
,
725 &fsize
->stepwise
.step_height
);
729 static int vidioc_g_fmt(struct vim2m_ctx
*ctx
, struct v4l2_format
*f
)
731 struct vb2_queue
*vq
;
732 struct vim2m_q_data
*q_data
;
734 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, f
->type
);
738 q_data
= get_q_data(ctx
, f
->type
);
742 f
->fmt
.pix
.width
= q_data
->width
;
743 f
->fmt
.pix
.height
= q_data
->height
;
744 f
->fmt
.pix
.field
= V4L2_FIELD_NONE
;
745 f
->fmt
.pix
.pixelformat
= q_data
->fmt
->fourcc
;
746 f
->fmt
.pix
.bytesperline
= (q_data
->width
* q_data
->fmt
->depth
) >> 3;
747 f
->fmt
.pix
.sizeimage
= q_data
->sizeimage
;
748 f
->fmt
.pix
.colorspace
= ctx
->colorspace
;
749 f
->fmt
.pix
.xfer_func
= ctx
->xfer_func
;
750 f
->fmt
.pix
.ycbcr_enc
= ctx
->ycbcr_enc
;
751 f
->fmt
.pix
.quantization
= ctx
->quant
;
756 static int vidioc_g_fmt_vid_out(struct file
*file
, void *priv
,
757 struct v4l2_format
*f
)
759 return vidioc_g_fmt(file2ctx(file
), f
);
762 static int vidioc_g_fmt_vid_cap(struct file
*file
, void *priv
,
763 struct v4l2_format
*f
)
765 return vidioc_g_fmt(file2ctx(file
), f
);
768 static int vidioc_try_fmt(struct v4l2_format
*f
, struct vim2m_fmt
*fmt
)
772 * V4L2 specification specifies the driver corrects the
773 * format struct if any of the dimensions is unsupported
775 if (f
->fmt
.pix
.height
< MIN_H
)
776 f
->fmt
.pix
.height
= MIN_H
;
777 else if (f
->fmt
.pix
.height
> MAX_H
)
778 f
->fmt
.pix
.height
= MAX_H
;
780 if (f
->fmt
.pix
.width
< MIN_W
)
781 f
->fmt
.pix
.width
= MIN_W
;
782 else if (f
->fmt
.pix
.width
> MAX_W
)
783 f
->fmt
.pix
.width
= MAX_W
;
785 get_alignment(f
->fmt
.pix
.pixelformat
, &walign
, &halign
);
786 f
->fmt
.pix
.width
&= ~(walign
- 1);
787 f
->fmt
.pix
.height
&= ~(halign
- 1);
788 f
->fmt
.pix
.bytesperline
= (f
->fmt
.pix
.width
* fmt
->depth
) >> 3;
789 f
->fmt
.pix
.sizeimage
= f
->fmt
.pix
.height
* f
->fmt
.pix
.bytesperline
;
790 f
->fmt
.pix
.field
= V4L2_FIELD_NONE
;
795 static int vidioc_try_fmt_vid_cap(struct file
*file
, void *priv
,
796 struct v4l2_format
*f
)
798 struct vim2m_fmt
*fmt
;
799 struct vim2m_ctx
*ctx
= file2ctx(file
);
801 fmt
= find_format(f
->fmt
.pix
.pixelformat
);
803 f
->fmt
.pix
.pixelformat
= formats
[0].fourcc
;
804 fmt
= find_format(f
->fmt
.pix
.pixelformat
);
806 if (!(fmt
->types
& MEM2MEM_CAPTURE
)) {
807 v4l2_err(&ctx
->dev
->v4l2_dev
,
808 "Fourcc format (0x%08x) invalid.\n",
809 f
->fmt
.pix
.pixelformat
);
812 f
->fmt
.pix
.colorspace
= ctx
->colorspace
;
813 f
->fmt
.pix
.xfer_func
= ctx
->xfer_func
;
814 f
->fmt
.pix
.ycbcr_enc
= ctx
->ycbcr_enc
;
815 f
->fmt
.pix
.quantization
= ctx
->quant
;
817 return vidioc_try_fmt(f
, fmt
);
820 static int vidioc_try_fmt_vid_out(struct file
*file
, void *priv
,
821 struct v4l2_format
*f
)
823 struct vim2m_fmt
*fmt
;
824 struct vim2m_ctx
*ctx
= file2ctx(file
);
826 fmt
= find_format(f
->fmt
.pix
.pixelformat
);
828 f
->fmt
.pix
.pixelformat
= formats
[0].fourcc
;
829 fmt
= find_format(f
->fmt
.pix
.pixelformat
);
831 if (!(fmt
->types
& MEM2MEM_OUTPUT
)) {
832 v4l2_err(&ctx
->dev
->v4l2_dev
,
833 "Fourcc format (0x%08x) invalid.\n",
834 f
->fmt
.pix
.pixelformat
);
837 if (!f
->fmt
.pix
.colorspace
)
838 f
->fmt
.pix
.colorspace
= V4L2_COLORSPACE_REC709
;
840 return vidioc_try_fmt(f
, fmt
);
843 static int vidioc_s_fmt(struct vim2m_ctx
*ctx
, struct v4l2_format
*f
)
845 struct vim2m_q_data
*q_data
;
846 struct vb2_queue
*vq
;
848 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, f
->type
);
852 q_data
= get_q_data(ctx
, f
->type
);
856 if (vb2_is_busy(vq
)) {
857 v4l2_err(&ctx
->dev
->v4l2_dev
, "%s queue busy\n", __func__
);
861 q_data
->fmt
= find_format(f
->fmt
.pix
.pixelformat
);
862 q_data
->width
= f
->fmt
.pix
.width
;
863 q_data
->height
= f
->fmt
.pix
.height
;
864 q_data
->sizeimage
= q_data
->width
* q_data
->height
865 * q_data
->fmt
->depth
>> 3;
868 "Format for type %s: %dx%d (%d bpp), fmt: %c%c%c%c\n",
869 type_name(f
->type
), q_data
->width
, q_data
->height
,
871 (q_data
->fmt
->fourcc
& 0xff),
872 (q_data
->fmt
->fourcc
>> 8) & 0xff,
873 (q_data
->fmt
->fourcc
>> 16) & 0xff,
874 (q_data
->fmt
->fourcc
>> 24) & 0xff);
879 static int vidioc_s_fmt_vid_cap(struct file
*file
, void *priv
,
880 struct v4l2_format
*f
)
884 ret
= vidioc_try_fmt_vid_cap(file
, priv
, f
);
888 return vidioc_s_fmt(file2ctx(file
), f
);
891 static int vidioc_s_fmt_vid_out(struct file
*file
, void *priv
,
892 struct v4l2_format
*f
)
894 struct vim2m_ctx
*ctx
= file2ctx(file
);
897 ret
= vidioc_try_fmt_vid_out(file
, priv
, f
);
901 ret
= vidioc_s_fmt(file2ctx(file
), f
);
903 ctx
->colorspace
= f
->fmt
.pix
.colorspace
;
904 ctx
->xfer_func
= f
->fmt
.pix
.xfer_func
;
905 ctx
->ycbcr_enc
= f
->fmt
.pix
.ycbcr_enc
;
906 ctx
->quant
= f
->fmt
.pix
.quantization
;
911 static int vim2m_s_ctrl(struct v4l2_ctrl
*ctrl
)
913 struct vim2m_ctx
*ctx
=
914 container_of(ctrl
->handler
, struct vim2m_ctx
, hdl
);
919 ctx
->mode
|= MEM2MEM_HFLIP
;
921 ctx
->mode
&= ~MEM2MEM_HFLIP
;
926 ctx
->mode
|= MEM2MEM_VFLIP
;
928 ctx
->mode
&= ~MEM2MEM_VFLIP
;
931 case V4L2_CID_TRANS_TIME_MSEC
:
932 ctx
->transtime
= ctrl
->val
;
933 if (ctx
->transtime
< 1)
937 case V4L2_CID_TRANS_NUM_BUFS
:
938 ctx
->translen
= ctrl
->val
;
942 v4l2_err(&ctx
->dev
->v4l2_dev
, "Invalid control\n");
949 static const struct v4l2_ctrl_ops vim2m_ctrl_ops
= {
950 .s_ctrl
= vim2m_s_ctrl
,
953 static const struct v4l2_ioctl_ops vim2m_ioctl_ops
= {
954 .vidioc_querycap
= vidioc_querycap
,
956 .vidioc_enum_fmt_vid_cap
= vidioc_enum_fmt_vid_cap
,
957 .vidioc_enum_framesizes
= vidioc_enum_framesizes
,
958 .vidioc_g_fmt_vid_cap
= vidioc_g_fmt_vid_cap
,
959 .vidioc_try_fmt_vid_cap
= vidioc_try_fmt_vid_cap
,
960 .vidioc_s_fmt_vid_cap
= vidioc_s_fmt_vid_cap
,
962 .vidioc_enum_fmt_vid_out
= vidioc_enum_fmt_vid_out
,
963 .vidioc_g_fmt_vid_out
= vidioc_g_fmt_vid_out
,
964 .vidioc_try_fmt_vid_out
= vidioc_try_fmt_vid_out
,
965 .vidioc_s_fmt_vid_out
= vidioc_s_fmt_vid_out
,
967 .vidioc_reqbufs
= v4l2_m2m_ioctl_reqbufs
,
968 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
969 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
970 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
971 .vidioc_prepare_buf
= v4l2_m2m_ioctl_prepare_buf
,
972 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
973 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
975 .vidioc_streamon
= v4l2_m2m_ioctl_streamon
,
976 .vidioc_streamoff
= v4l2_m2m_ioctl_streamoff
,
978 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
979 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
986 static int vim2m_queue_setup(struct vb2_queue
*vq
,
987 unsigned int *nbuffers
,
988 unsigned int *nplanes
,
989 unsigned int sizes
[],
990 struct device
*alloc_devs
[])
992 struct vim2m_ctx
*ctx
= vb2_get_drv_priv(vq
);
993 struct vim2m_q_data
*q_data
;
994 unsigned int size
, count
= *nbuffers
;
996 q_data
= get_q_data(ctx
, vq
->type
);
1000 size
= q_data
->width
* q_data
->height
* q_data
->fmt
->depth
>> 3;
1002 while (size
* count
> MEM2MEM_VID_MEM_LIMIT
)
1007 return sizes
[0] < size
? -EINVAL
: 0;
1012 dprintk(ctx
->dev
, 1, "%s: get %d buffer(s) of size %d each.\n",
1013 type_name(vq
->type
), count
, size
);
1018 static int vim2m_buf_out_validate(struct vb2_buffer
*vb
)
1020 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
1021 struct vim2m_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
1023 if (vbuf
->field
== V4L2_FIELD_ANY
)
1024 vbuf
->field
= V4L2_FIELD_NONE
;
1025 if (vbuf
->field
!= V4L2_FIELD_NONE
) {
1026 dprintk(ctx
->dev
, 1, "%s field isn't supported\n", __func__
);
1033 static int vim2m_buf_prepare(struct vb2_buffer
*vb
)
1035 struct vim2m_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
1036 struct vim2m_q_data
*q_data
;
1038 dprintk(ctx
->dev
, 2, "type: %s\n", type_name(vb
->vb2_queue
->type
));
1040 q_data
= get_q_data(ctx
, vb
->vb2_queue
->type
);
1043 if (vb2_plane_size(vb
, 0) < q_data
->sizeimage
) {
1044 dprintk(ctx
->dev
, 1,
1045 "%s data will not fit into plane (%lu < %lu)\n",
1046 __func__
, vb2_plane_size(vb
, 0),
1047 (long)q_data
->sizeimage
);
1051 vb2_set_plane_payload(vb
, 0, q_data
->sizeimage
);
1056 static void vim2m_buf_queue(struct vb2_buffer
*vb
)
1058 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
1059 struct vim2m_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
1061 v4l2_m2m_buf_queue(ctx
->fh
.m2m_ctx
, vbuf
);
1064 static int vim2m_start_streaming(struct vb2_queue
*q
, unsigned int count
)
1066 struct vim2m_ctx
*ctx
= vb2_get_drv_priv(q
);
1067 struct vim2m_q_data
*q_data
= get_q_data(ctx
, q
->type
);
1072 if (V4L2_TYPE_IS_OUTPUT(q
->type
))
1075 q_data
->sequence
= 0;
1079 static void vim2m_stop_streaming(struct vb2_queue
*q
)
1081 struct vim2m_ctx
*ctx
= vb2_get_drv_priv(q
);
1082 struct vb2_v4l2_buffer
*vbuf
;
1084 cancel_delayed_work_sync(&ctx
->work_run
);
1087 if (V4L2_TYPE_IS_OUTPUT(q
->type
))
1088 vbuf
= v4l2_m2m_src_buf_remove(ctx
->fh
.m2m_ctx
);
1090 vbuf
= v4l2_m2m_dst_buf_remove(ctx
->fh
.m2m_ctx
);
1093 v4l2_ctrl_request_complete(vbuf
->vb2_buf
.req_obj
.req
,
1095 v4l2_m2m_buf_done(vbuf
, VB2_BUF_STATE_ERROR
);
1099 static void vim2m_buf_request_complete(struct vb2_buffer
*vb
)
1101 struct vim2m_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
1103 v4l2_ctrl_request_complete(vb
->req_obj
.req
, &ctx
->hdl
);
1106 static const struct vb2_ops vim2m_qops
= {
1107 .queue_setup
= vim2m_queue_setup
,
1108 .buf_out_validate
= vim2m_buf_out_validate
,
1109 .buf_prepare
= vim2m_buf_prepare
,
1110 .buf_queue
= vim2m_buf_queue
,
1111 .start_streaming
= vim2m_start_streaming
,
1112 .stop_streaming
= vim2m_stop_streaming
,
1113 .wait_prepare
= vb2_ops_wait_prepare
,
1114 .wait_finish
= vb2_ops_wait_finish
,
1115 .buf_request_complete
= vim2m_buf_request_complete
,
1118 static int queue_init(void *priv
, struct vb2_queue
*src_vq
,
1119 struct vb2_queue
*dst_vq
)
1121 struct vim2m_ctx
*ctx
= priv
;
1124 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
1125 src_vq
->io_modes
= VB2_MMAP
| VB2_USERPTR
| VB2_DMABUF
;
1126 src_vq
->drv_priv
= ctx
;
1127 src_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
1128 src_vq
->ops
= &vim2m_qops
;
1129 src_vq
->mem_ops
= &vb2_vmalloc_memops
;
1130 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
1131 src_vq
->lock
= &ctx
->vb_mutex
;
1132 src_vq
->supports_requests
= true;
1134 ret
= vb2_queue_init(src_vq
);
1138 dst_vq
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
1139 dst_vq
->io_modes
= VB2_MMAP
| VB2_USERPTR
| VB2_DMABUF
;
1140 dst_vq
->drv_priv
= ctx
;
1141 dst_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
1142 dst_vq
->ops
= &vim2m_qops
;
1143 dst_vq
->mem_ops
= &vb2_vmalloc_memops
;
1144 dst_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
1145 dst_vq
->lock
= &ctx
->vb_mutex
;
1147 return vb2_queue_init(dst_vq
);
1150 static struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec
= {
1151 .ops
= &vim2m_ctrl_ops
,
1152 .id
= V4L2_CID_TRANS_TIME_MSEC
,
1153 .name
= "Transaction Time (msec)",
1154 .type
= V4L2_CTRL_TYPE_INTEGER
,
1160 static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs
= {
1161 .ops
= &vim2m_ctrl_ops
,
1162 .id
= V4L2_CID_TRANS_NUM_BUFS
,
1163 .name
= "Buffers Per Transaction",
1164 .type
= V4L2_CTRL_TYPE_INTEGER
,
1167 .max
= MEM2MEM_DEF_NUM_BUFS
,
1174 static int vim2m_open(struct file
*file
)
1176 struct vim2m_dev
*dev
= video_drvdata(file
);
1177 struct vim2m_ctx
*ctx
= NULL
;
1178 struct v4l2_ctrl_handler
*hdl
;
1181 if (mutex_lock_interruptible(&dev
->dev_mutex
))
1182 return -ERESTARTSYS
;
1183 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
1189 v4l2_fh_init(&ctx
->fh
, video_devdata(file
));
1190 file
->private_data
= &ctx
->fh
;
1193 v4l2_ctrl_handler_init(hdl
, 4);
1194 v4l2_ctrl_new_std(hdl
, &vim2m_ctrl_ops
, V4L2_CID_HFLIP
, 0, 1, 1, 0);
1195 v4l2_ctrl_new_std(hdl
, &vim2m_ctrl_ops
, V4L2_CID_VFLIP
, 0, 1, 1, 0);
1197 vim2m_ctrl_trans_time_msec
.def
= default_transtime
;
1198 v4l2_ctrl_new_custom(hdl
, &vim2m_ctrl_trans_time_msec
, NULL
);
1199 v4l2_ctrl_new_custom(hdl
, &vim2m_ctrl_trans_num_bufs
, NULL
);
1202 v4l2_ctrl_handler_free(hdl
);
1206 ctx
->fh
.ctrl_handler
= hdl
;
1207 v4l2_ctrl_handler_setup(hdl
);
1209 ctx
->q_data
[V4L2_M2M_SRC
].fmt
= &formats
[0];
1210 ctx
->q_data
[V4L2_M2M_SRC
].width
= 640;
1211 ctx
->q_data
[V4L2_M2M_SRC
].height
= 480;
1212 ctx
->q_data
[V4L2_M2M_SRC
].sizeimage
=
1213 ctx
->q_data
[V4L2_M2M_SRC
].width
*
1214 ctx
->q_data
[V4L2_M2M_SRC
].height
*
1215 (ctx
->q_data
[V4L2_M2M_SRC
].fmt
->depth
>> 3);
1216 ctx
->q_data
[V4L2_M2M_DST
] = ctx
->q_data
[V4L2_M2M_SRC
];
1217 ctx
->colorspace
= V4L2_COLORSPACE_REC709
;
1219 ctx
->fh
.m2m_ctx
= v4l2_m2m_ctx_init(dev
->m2m_dev
, ctx
, &queue_init
);
1221 mutex_init(&ctx
->vb_mutex
);
1222 INIT_DELAYED_WORK(&ctx
->work_run
, device_work
);
1224 if (IS_ERR(ctx
->fh
.m2m_ctx
)) {
1225 rc
= PTR_ERR(ctx
->fh
.m2m_ctx
);
1227 v4l2_ctrl_handler_free(hdl
);
1228 v4l2_fh_exit(&ctx
->fh
);
1233 v4l2_fh_add(&ctx
->fh
);
1234 atomic_inc(&dev
->num_inst
);
1236 dprintk(dev
, 1, "Created instance: %p, m2m_ctx: %p\n",
1237 ctx
, ctx
->fh
.m2m_ctx
);
1240 mutex_unlock(&dev
->dev_mutex
);
1244 static int vim2m_release(struct file
*file
)
1246 struct vim2m_dev
*dev
= video_drvdata(file
);
1247 struct vim2m_ctx
*ctx
= file2ctx(file
);
1249 dprintk(dev
, 1, "Releasing instance %p\n", ctx
);
1251 v4l2_fh_del(&ctx
->fh
);
1252 v4l2_fh_exit(&ctx
->fh
);
1253 v4l2_ctrl_handler_free(&ctx
->hdl
);
1254 mutex_lock(&dev
->dev_mutex
);
1255 v4l2_m2m_ctx_release(ctx
->fh
.m2m_ctx
);
1256 mutex_unlock(&dev
->dev_mutex
);
1259 atomic_dec(&dev
->num_inst
);
1264 static void vim2m_device_release(struct video_device
*vdev
)
1266 struct vim2m_dev
*dev
= container_of(vdev
, struct vim2m_dev
, vfd
);
1268 v4l2_device_unregister(&dev
->v4l2_dev
);
1269 v4l2_m2m_release(dev
->m2m_dev
);
1270 #ifdef CONFIG_MEDIA_CONTROLLER
1271 media_device_cleanup(&dev
->mdev
);
1276 static const struct v4l2_file_operations vim2m_fops
= {
1277 .owner
= THIS_MODULE
,
1279 .release
= vim2m_release
,
1280 .poll
= v4l2_m2m_fop_poll
,
1281 .unlocked_ioctl
= video_ioctl2
,
1282 .mmap
= v4l2_m2m_fop_mmap
,
1285 static const struct video_device vim2m_videodev
= {
1286 .name
= MEM2MEM_NAME
,
1287 .vfl_dir
= VFL_DIR_M2M
,
1288 .fops
= &vim2m_fops
,
1289 .ioctl_ops
= &vim2m_ioctl_ops
,
1291 .release
= vim2m_device_release
,
1292 .device_caps
= V4L2_CAP_VIDEO_M2M
| V4L2_CAP_STREAMING
,
1295 static const struct v4l2_m2m_ops m2m_ops
= {
1296 .device_run
= device_run
,
1297 .job_ready
= job_ready
,
1298 .job_abort
= job_abort
,
1301 static const struct media_device_ops m2m_media_ops
= {
1302 .req_validate
= vb2_request_validate
,
1303 .req_queue
= v4l2_m2m_request_queue
,
1306 static int vim2m_probe(struct platform_device
*pdev
)
1308 struct vim2m_dev
*dev
;
1309 struct video_device
*vfd
;
1312 dev
= kzalloc(sizeof(*dev
), GFP_KERNEL
);
1316 ret
= v4l2_device_register(&pdev
->dev
, &dev
->v4l2_dev
);
1320 atomic_set(&dev
->num_inst
, 0);
1321 mutex_init(&dev
->dev_mutex
);
1323 dev
->vfd
= vim2m_videodev
;
1325 vfd
->lock
= &dev
->dev_mutex
;
1326 vfd
->v4l2_dev
= &dev
->v4l2_dev
;
1328 video_set_drvdata(vfd
, dev
);
1329 v4l2_info(&dev
->v4l2_dev
,
1330 "Device registered as /dev/video%d\n", vfd
->num
);
1332 platform_set_drvdata(pdev
, dev
);
1334 dev
->m2m_dev
= v4l2_m2m_init(&m2m_ops
);
1335 if (IS_ERR(dev
->m2m_dev
)) {
1336 v4l2_err(&dev
->v4l2_dev
, "Failed to init mem2mem device\n");
1337 ret
= PTR_ERR(dev
->m2m_dev
);
1338 dev
->m2m_dev
= NULL
;
1342 ret
= video_register_device(vfd
, VFL_TYPE_VIDEO
, 0);
1344 v4l2_err(&dev
->v4l2_dev
, "Failed to register video device\n");
1348 #ifdef CONFIG_MEDIA_CONTROLLER
1349 dev
->mdev
.dev
= &pdev
->dev
;
1350 strscpy(dev
->mdev
.model
, "vim2m", sizeof(dev
->mdev
.model
));
1351 strscpy(dev
->mdev
.bus_info
, "platform:vim2m",
1352 sizeof(dev
->mdev
.bus_info
));
1353 media_device_init(&dev
->mdev
);
1354 dev
->mdev
.ops
= &m2m_media_ops
;
1355 dev
->v4l2_dev
.mdev
= &dev
->mdev
;
1357 ret
= v4l2_m2m_register_media_controller(dev
->m2m_dev
, vfd
,
1358 MEDIA_ENT_F_PROC_VIDEO_SCALER
);
1360 v4l2_err(&dev
->v4l2_dev
, "Failed to init mem2mem media controller\n");
1364 ret
= media_device_register(&dev
->mdev
);
1366 v4l2_err(&dev
->v4l2_dev
, "Failed to register mem2mem media device\n");
1372 #ifdef CONFIG_MEDIA_CONTROLLER
1374 v4l2_m2m_unregister_media_controller(dev
->m2m_dev
);
1377 video_unregister_device(&dev
->vfd
);
1378 /* vim2m_device_release called by video_unregister_device to release various objects */
1381 v4l2_m2m_release(dev
->m2m_dev
);
1383 v4l2_device_unregister(&dev
->v4l2_dev
);
1390 static int vim2m_remove(struct platform_device
*pdev
)
1392 struct vim2m_dev
*dev
= platform_get_drvdata(pdev
);
1394 v4l2_info(&dev
->v4l2_dev
, "Removing " MEM2MEM_NAME
);
1396 #ifdef CONFIG_MEDIA_CONTROLLER
1397 media_device_unregister(&dev
->mdev
);
1398 v4l2_m2m_unregister_media_controller(dev
->m2m_dev
);
1400 video_unregister_device(&dev
->vfd
);
1405 static struct platform_driver vim2m_pdrv
= {
1406 .probe
= vim2m_probe
,
1407 .remove
= vim2m_remove
,
1409 .name
= MEM2MEM_NAME
,
1413 static void __exit
vim2m_exit(void)
1415 platform_driver_unregister(&vim2m_pdrv
);
1416 platform_device_unregister(&vim2m_pdev
);
1419 static int __init
vim2m_init(void)
1423 ret
= platform_device_register(&vim2m_pdev
);
1427 ret
= platform_driver_register(&vim2m_pdrv
);
1429 platform_device_unregister(&vim2m_pdev
);
1434 module_init(vim2m_init
);
1435 module_exit(vim2m_exit
);