blob: a27d3052bb62613dccb629f00443e1d0ba102052 [file] [log] [blame]
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001/*
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
Hans Verkuil144bd0e2018-05-21 04:54:56 -04006 * destination, processes the data and issues an "irq" (simulated by a delayed
7 * workqueue).
Pawel Osciak96d8eab2010-04-23 05:38:38 -03008 * The device is capable of multi-instance, multi-buffer-per-transaction
9 * operation (via the mem2mem framework).
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
Pawel Osciak95072082011-03-13 15:23:32 -030012 * Pawel Osciak, <pawel@osciak.com>
Pawel Osciak96d8eab2010-04-23 05:38:38 -030013 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 2 of the
18 * License, or (at your option) any later version
19 */
20#include <linux/module.h>
21#include <linux/delay.h>
22#include <linux/fs.h>
Pawel Osciak96d8eab2010-04-23 05:38:38 -030023#include <linux/sched.h>
Randy Dunlap6b46c392010-05-07 15:22:26 -030024#include <linux/slab.h>
Pawel Osciak96d8eab2010-04-23 05:38:38 -030025
26#include <linux/platform_device.h>
27#include <media/v4l2-mem2mem.h>
28#include <media/v4l2-device.h>
29#include <media/v4l2-ioctl.h>
Hans Verkuild3dd59c2012-07-18 10:35:37 -030030#include <media/v4l2-ctrls.h>
Hans Verkuil97a3c902012-07-18 10:54:59 -030031#include <media/v4l2-event.h>
Marek Szyprowskid80ee382011-01-12 06:50:55 -030032#include <media/videobuf2-vmalloc.h>
Pawel Osciak96d8eab2010-04-23 05:38:38 -030033
Pawel Osciak96d8eab2010-04-23 05:38:38 -030034MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
Pawel Osciak95072082011-03-13 15:23:32 -030035MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
Pawel Osciak96d8eab2010-04-23 05:38:38 -030036MODULE_LICENSE("GPL");
Mauro Carvalho Chehab1990d502011-06-24 14:45:49 -030037MODULE_VERSION("0.1.1");
Hans Verkuil1f923a42014-09-22 09:27:17 -030038MODULE_ALIAS("mem2mem_testdev");
Pawel Osciak96d8eab2010-04-23 05:38:38 -030039
Hans Verkuild95d7c62013-04-17 03:04:10 -030040static unsigned debug;
41module_param(debug, uint, 0644);
42MODULE_PARM_DESC(debug, "activates debug info");
43
Mauro Carvalho Chehabf0ef0222019-01-29 14:00:17 -020044/* Default transaction time in msec */
45static unsigned int default_transtime = 40; /* Max 25 fps */
46module_param(default_transtime, uint, 0644);
47MODULE_PARM_DESC(default_transtime, "default transaction time in ms");
48
Pawel Osciak96d8eab2010-04-23 05:38:38 -030049#define MIN_W 32
50#define MIN_H 32
51#define MAX_W 640
52#define MAX_H 480
Guennadi Liakhovetski9ce3ce4d42012-04-27 04:16:46 -030053#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */
Pawel Osciak96d8eab2010-04-23 05:38:38 -030054
55/* Flags that indicate a format can be used for capture/output */
56#define MEM2MEM_CAPTURE (1 << 0)
57#define MEM2MEM_OUTPUT (1 << 1)
58
Hans Verkuil1f923a42014-09-22 09:27:17 -030059#define MEM2MEM_NAME "vim2m"
Pawel Osciak96d8eab2010-04-23 05:38:38 -030060
61/* Per queue */
62#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME
63/* In bytes, per queue */
64#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024)
65
Tomasz Moń80072872012-06-12 06:43:49 -030066/* Flags that indicate processing mode */
67#define MEM2MEM_HFLIP (1 << 0)
68#define MEM2MEM_VFLIP (1 << 1)
69
Pawel Osciak96d8eab2010-04-23 05:38:38 -030070#define dprintk(dev, fmt, arg...) \
Hans Verkuild95d7c62013-04-17 03:04:10 -030071 v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
Pawel Osciak96d8eab2010-04-23 05:38:38 -030072
73
Hans Verkuil1f923a42014-09-22 09:27:17 -030074static void vim2m_dev_release(struct device *dev)
Pawel Osciak96d8eab2010-04-23 05:38:38 -030075{}
76
Hans Verkuil1f923a42014-09-22 09:27:17 -030077static struct platform_device vim2m_pdev = {
Pawel Osciak96d8eab2010-04-23 05:38:38 -030078 .name = MEM2MEM_NAME,
Hans Verkuil1f923a42014-09-22 09:27:17 -030079 .dev.release = vim2m_dev_release,
Pawel Osciak96d8eab2010-04-23 05:38:38 -030080};
81
Hans Verkuil1f923a42014-09-22 09:27:17 -030082struct vim2m_fmt {
Pawel Osciak96d8eab2010-04-23 05:38:38 -030083 u32 fourcc;
84 int depth;
Pawel Osciak96d8eab2010-04-23 05:38:38 -030085};
86
Hans Verkuil1f923a42014-09-22 09:27:17 -030087static struct vim2m_fmt formats[] = {
Pawel Osciak96d8eab2010-04-23 05:38:38 -030088 {
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -020089 .fourcc = V4L2_PIX_FMT_RGB565, /* rrrrrggg gggbbbbb */
Pawel Osciak96d8eab2010-04-23 05:38:38 -030090 .depth = 16,
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -020091 }, {
92 .fourcc = V4L2_PIX_FMT_RGB565X, /* gggbbbbb rrrrrggg */
93 .depth = 16,
94 }, {
95 .fourcc = V4L2_PIX_FMT_RGB24,
96 .depth = 24,
97 }, {
98 .fourcc = V4L2_PIX_FMT_BGR24,
99 .depth = 24,
100 }, {
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300101 .fourcc = V4L2_PIX_FMT_YUYV,
102 .depth = 16,
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300103 },
104};
105
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300106#define NUM_FORMATS ARRAY_SIZE(formats)
107
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300108/* Per-queue, driver-specific private data */
Hans Verkuil1f923a42014-09-22 09:27:17 -0300109struct vim2m_q_data {
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300110 unsigned int width;
111 unsigned int height;
112 unsigned int sizeimage;
Hans Verkuilca5f5fd2014-03-10 10:58:28 -0300113 unsigned int sequence;
Hans Verkuil1f923a42014-09-22 09:27:17 -0300114 struct vim2m_fmt *fmt;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300115};
116
117enum {
118 V4L2_M2M_SRC = 0,
119 V4L2_M2M_DST = 1,
120};
121
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300122#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000)
123#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300124
Hans Verkuil1f923a42014-09-22 09:27:17 -0300125static struct vim2m_fmt *find_format(struct v4l2_format *f)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300126{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300127 struct vim2m_fmt *fmt;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300128 unsigned int k;
129
130 for (k = 0; k < NUM_FORMATS; k++) {
131 fmt = &formats[k];
132 if (fmt->fourcc == f->fmt.pix.pixelformat)
133 break;
134 }
135
136 if (k == NUM_FORMATS)
137 return NULL;
138
139 return &formats[k];
140}
141
Hans Verkuil1f923a42014-09-22 09:27:17 -0300142struct vim2m_dev {
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300143 struct v4l2_device v4l2_dev;
Hans Verkuil09365422015-03-09 13:33:56 -0300144 struct video_device vfd;
Hans Verkuile35f7022018-07-02 11:36:06 -0400145#ifdef CONFIG_MEDIA_CONTROLLER
146 struct media_device mdev;
147#endif
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300148
149 atomic_t num_inst;
150 struct mutex dev_mutex;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300151
152 struct v4l2_m2m_dev *m2m_dev;
153};
154
Hans Verkuil1f923a42014-09-22 09:27:17 -0300155struct vim2m_ctx {
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300156 struct v4l2_fh fh;
Hans Verkuil1f923a42014-09-22 09:27:17 -0300157 struct vim2m_dev *dev;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300158
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300159 struct v4l2_ctrl_handler hdl;
160
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300161 /* Processed buffers in this transaction */
162 u8 num_processed;
163
164 /* Transaction length (i.e. how many buffers per transaction) */
165 u32 translen;
166 /* Transaction time (i.e. simulated processing time) in milliseconds */
167 u32 transtime;
168
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200169 struct mutex vb_mutex;
170 struct delayed_work work_run;
171 spinlock_t irqlock;
172
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300173 /* Abort requested by m2m */
174 int aborting;
175
Tomasz Moń80072872012-06-12 06:43:49 -0300176 /* Processing mode */
177 int mode;
178
Hans Verkuil47556ff2012-07-18 11:33:22 -0300179 enum v4l2_colorspace colorspace;
Hans Verkuil9f8b3332016-07-18 08:00:20 -0300180 enum v4l2_ycbcr_encoding ycbcr_enc;
181 enum v4l2_xfer_func xfer_func;
182 enum v4l2_quantization quant;
Hans Verkuil47556ff2012-07-18 11:33:22 -0300183
Tomasz Moń9f4161a2012-06-08 04:47:34 -0300184 /* Source and destination queue data */
Hans Verkuil1f923a42014-09-22 09:27:17 -0300185 struct vim2m_q_data q_data[2];
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300186};
187
Hans Verkuil1f923a42014-09-22 09:27:17 -0300188static inline struct vim2m_ctx *file2ctx(struct file *file)
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300189{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300190 return container_of(file->private_data, struct vim2m_ctx, fh);
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300191}
192
Hans Verkuil1f923a42014-09-22 09:27:17 -0300193static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx,
Tomasz Moń9f4161a2012-06-08 04:47:34 -0300194 enum v4l2_buf_type type)
195{
196 switch (type) {
197 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
198 return &ctx->q_data[V4L2_M2M_SRC];
199 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
200 return &ctx->q_data[V4L2_M2M_DST];
201 default:
202 BUG();
203 }
204 return NULL;
205}
206
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200207#define CLIP(__color) \
208 (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color)))
209
210static void copy_two_pixels(struct vim2m_fmt *in, struct vim2m_fmt *out,
211 u8 **src, u8 **dst, bool reverse)
212{
213 u8 _r[2], _g[2], _b[2], *r, *g, *b;
214 int i, step;
215
216 // If format is the same just copy the data, respecting the width
217 if (in->fourcc == out->fourcc) {
218 int depth = out->depth >> 3;
219
220 if (reverse) {
221 if (in->fourcc == V4L2_PIX_FMT_YUYV) {
222 int u, v, y, y1;
223
224 *src -= 2;
225
226 y1 = (*src)[0]; /* copy as second point */
227 u = (*src)[1];
228 y = (*src)[2]; /* copy as first point */
229 v = (*src)[3];
230
231 *src -= 2;
232
233 *(*dst)++ = y;
234 *(*dst)++ = u;
235 *(*dst)++ = y1;
236 *(*dst)++ = v;
237 return;
238 }
239
240 memcpy(*dst, *src, depth);
241 memcpy(*dst + depth, *src - depth, depth);
242 *src -= depth << 1;
243 } else {
244 memcpy(*dst, *src, depth << 1);
245 *src += depth << 1;
246 }
247 *dst += depth << 1;
248 return;
249 }
250
251 /* Step 1: read two consecutive pixels from src pointer */
252
253 r = _r;
254 g = _g;
255 b = _b;
256
257 if (reverse)
258 step = -1;
259 else
260 step = 1;
261
262 switch (in->fourcc) {
263 case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
264 for (i = 0; i < 2; i++) {
265 u16 pix = *(u16 *)*src;
266
267 *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07;
268 *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03;
269 *b++ = (u8)((pix & 0x1f) << 3) | 0x07;
270
271 *src += step << 1;
272 }
273 break;
274 case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
275 for (i = 0; i < 2; i++) {
276 u16 pix = *(u16 *)*src;
277
278 *r++ = (u8)(((0x00f8 & pix) >> 3) << 3) | 0x07;
279 *g++ = (u8)(((pix & 0x7) << 2) |
280 ((pix & 0xe000) >> 5)) | 0x03;
281 *b++ = (u8)(((pix & 0x1f00) >> 8) << 3) | 0x07;
282
283 *src += step << 1;
284 }
285 break;
286 case V4L2_PIX_FMT_RGB24:
287 for (i = 0; i < 2; i++) {
288 *r++ = (*src)[0];
289 *g++ = (*src)[1];
290 *b++ = (*src)[2];
291
292 *src += step * 3;
293 }
294 break;
295 case V4L2_PIX_FMT_BGR24:
296 for (i = 0; i < 2; i++) {
297 *b++ = (*src)[0];
298 *g++ = (*src)[1];
299 *r++ = (*src)[2];
300
301 *src += step * 3;
302 }
303 break;
304 default: /* V4L2_PIX_FMT_YUYV */
305 {
306 int u, v, y, y1, u1, v1, tmp;
307
308 if (reverse) {
309 *src -= 2;
310
311 y1 = (*src)[0]; /* copy as second point */
312 u = (*src)[1];
313 y = (*src)[2]; /* copy as first point */
314 v = (*src)[3];
315
316 *src -= 2;
317 } else {
318 y = *(*src)++;
319 u = *(*src)++;
320 y1 = *(*src)++;
321 v = *(*src)++;
322 }
323
324 u1 = (((u - 128) << 7) + (u - 128)) >> 6;
325 tmp = (((u - 128) << 1) + (u - 128) +
326 ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
327 v1 = (((v - 128) << 1) + (v - 128)) >> 1;
328
329 *r++ = CLIP(y + v1);
330 *g++ = CLIP(y - tmp);
331 *b++ = CLIP(y + u1);
332
333 *r = CLIP(y1 + v1);
334 *g = CLIP(y1 - tmp);
335 *b = CLIP(y1 + u1);
336 break;
337 }
338 }
339
340 /* Step 2: store two consecutive points, reversing them if needed */
341
342 r = _r;
343 g = _g;
344 b = _b;
345
346 switch (out->fourcc) {
347 case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
348 for (i = 0; i < 2; i++) {
349 u16 *pix = (u16 *)*dst;
350
351 *pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) |
352 (*b >> 3);
353
354 *dst += 2;
355 }
356 return;
357 case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
358 for (i = 0; i < 2; i++) {
359 u16 *pix = (u16 *)*dst;
360 u8 green = *g++ >> 2;
361
362 *pix = ((green << 8) & 0xe000) | (green & 0x07) |
363 ((*b++ << 5) & 0x1f00) | ((*r++ & 0xf8));
364
365 *dst += 2;
366 }
367 return;
368 case V4L2_PIX_FMT_RGB24:
369 for (i = 0; i < 2; i++) {
370 *(*dst)++ = *r++;
371 *(*dst)++ = *g++;
372 *(*dst)++ = *b++;
373 }
374 return;
375 case V4L2_PIX_FMT_BGR24:
376 for (i = 0; i < 2; i++) {
377 *(*dst)++ = *b++;
378 *(*dst)++ = *g++;
379 *(*dst)++ = *r++;
380 }
381 return;
382 default: /* V4L2_PIX_FMT_YUYV */
383 {
384 u8 y, y1, u, v;
385
386 y = ((8453 * (*r) + 16594 * (*g) + 3223 * (*b)
387 + 524288) >> 15);
388 u = ((-4878 * (*r) - 9578 * (*g) + 14456 * (*b)
389 + 4210688) >> 15);
390 v = ((14456 * (*r++) - 12105 * (*g++) - 2351 * (*b++)
391 + 4210688) >> 15);
392 y1 = ((8453 * (*r) + 16594 * (*g) + 3223 * (*b)
393 + 524288) >> 15);
394
395 *(*dst)++ = y;
396 *(*dst)++ = u;
397
398 *(*dst)++ = y1;
399 *(*dst)++ = v;
400 return;
401 }
402 }
403}
Tomasz Moń9f4161a2012-06-08 04:47:34 -0300404
Hans Verkuil1f923a42014-09-22 09:27:17 -0300405static int device_process(struct vim2m_ctx *ctx,
Junghak Sung2d700712015-09-22 10:30:30 -0300406 struct vb2_v4l2_buffer *in_vb,
407 struct vb2_v4l2_buffer *out_vb)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300408{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300409 struct vim2m_dev *dev = ctx->dev;
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200410 struct vim2m_q_data *q_data_in, *q_data_out;
411 u8 *p_in, *p, *p_out;
412 int width, height, bytesperline, x, y, start, end, step;
413 struct vim2m_fmt *in, *out;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300414
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200415 q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
416 in = q_data_in->fmt;
417 width = q_data_in->width;
418 height = q_data_in->height;
419 bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300420
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200421 q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
422 out = q_data_out->fmt;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300423
Junghak Sung2d700712015-09-22 10:30:30 -0300424 p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
425 p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300426 if (!p_in || !p_out) {
427 v4l2_err(&dev->v4l2_dev,
428 "Acquiring kernel pointers to buffers failed\n");
429 return -EFAULT;
430 }
431
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200432 out_vb->sequence = get_q_data(ctx,
433 V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
434 in_vb->sequence = q_data_in->sequence++;
Ezequiel Garciaa4d3d612019-02-05 16:20:33 -0500435 v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true);
Hans Verkuild95d7c62013-04-17 03:04:10 -0300436
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200437 if (ctx->mode & MEM2MEM_VFLIP) {
438 start = height - 1;
439 end = -1;
440 step = -1;
441 } else {
442 start = 0;
443 end = height;
444 step = 1;
445 }
446 for (y = start; y != end; y += step) {
447 p = p_in + (y * bytesperline);
448 if (ctx->mode & MEM2MEM_HFLIP)
449 p += bytesperline - (q_data_in->fmt->depth >> 3);
Tomasz Moń80072872012-06-12 06:43:49 -0300450
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200451 for (x = 0; x < width >> 1; x++)
452 copy_two_pixels(in, out, &p, &p_out,
453 ctx->mode & MEM2MEM_HFLIP);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300454 }
455
456 return 0;
457}
458
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300459/*
460 * mem2mem callbacks
461 */
462
Mauro Carvalho Chehabcba862d2017-11-29 08:33:45 -0500463/*
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300464 * job_ready() - check whether an instance is ready to be scheduled to run
465 */
466static int job_ready(void *priv)
467{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300468 struct vim2m_ctx *ctx = priv;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300469
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -0300470 if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen
471 || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) {
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300472 dprintk(ctx->dev, "Not enough buffers available\n");
473 return 0;
474 }
475
476 return 1;
477}
478
479static void job_abort(void *priv)
480{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300481 struct vim2m_ctx *ctx = priv;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300482
483 /* Will cancel the transaction in the next interrupt handler */
484 ctx->aborting = 1;
485}
486
487/* device_run() - prepares and starts the device
488 *
489 * This simulates all the immediate preparations required before starting
490 * a device. This will be called by the framework when it decides to schedule
491 * a particular instance.
492 */
493static void device_run(void *priv)
494{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300495 struct vim2m_ctx *ctx = priv;
Junghak Sung2d700712015-09-22 10:30:30 -0300496 struct vb2_v4l2_buffer *src_buf, *dst_buf;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300497
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -0300498 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
499 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300500
Hans Verkuil86b93b22018-05-21 04:54:57 -0400501 /* Apply request controls if any */
502 v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
503 &ctx->hdl);
504
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300505 device_process(ctx, src_buf, dst_buf);
506
Hans Verkuil86b93b22018-05-21 04:54:57 -0400507 /* Complete request controls if any */
508 v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
509 &ctx->hdl);
510
Hans Verkuil144bd0e2018-05-21 04:54:56 -0400511 /* Run delayed work, which simulates a hardware irq */
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200512 schedule_delayed_work(&ctx->work_run, msecs_to_jiffies(ctx->transtime));
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300513}
514
Hans Verkuil144bd0e2018-05-21 04:54:56 -0400515static void device_work(struct work_struct *w)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300516{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300517 struct vim2m_ctx *curr_ctx;
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200518 struct vim2m_dev *vim2m_dev;
Junghak Sung2d700712015-09-22 10:30:30 -0300519 struct vb2_v4l2_buffer *src_vb, *dst_vb;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300520 unsigned long flags;
521
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200522 curr_ctx = container_of(w, struct vim2m_ctx, work_run.work);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300523
524 if (NULL == curr_ctx) {
Sachin Kamat26fdcf02012-09-24 02:17:47 -0300525 pr_err("Instance released before the end of transaction\n");
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300526 return;
527 }
528
Mauro Carvalho Chehab22f05d62019-02-07 12:28:19 -0500529 vim2m_dev = curr_ctx->dev;
530
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -0300531 src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
532 dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300533
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300534 curr_ctx->num_processed++;
535
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200536 spin_lock_irqsave(&curr_ctx->irqlock, flags);
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300537 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
538 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200539 spin_unlock_irqrestore(&curr_ctx->irqlock, flags);
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300540
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300541 if (curr_ctx->num_processed == curr_ctx->translen
542 || curr_ctx->aborting) {
543 dprintk(curr_ctx->dev, "Finishing transaction\n");
544 curr_ctx->num_processed = 0;
Hans Verkuil1f923a42014-09-22 09:27:17 -0300545 v4l2_m2m_job_finish(vim2m_dev->m2m_dev, curr_ctx->fh.m2m_ctx);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300546 } else {
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300547 device_run(curr_ctx);
548 }
549}
550
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300551/*
552 * video ioctls
553 */
554static int vidioc_querycap(struct file *file, void *priv,
555 struct v4l2_capability *cap)
556{
557 strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
558 strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
Hans Verkuil72c2af62012-09-14 06:23:12 -0300559 snprintf(cap->bus_info, sizeof(cap->bus_info),
560 "platform:%s", MEM2MEM_NAME);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300561 return 0;
562}
563
564static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
565{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300566 struct vim2m_fmt *fmt;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300567
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200568 if (f->index < NUM_FORMATS) {
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300569 /* Format found */
Mauro Carvalho Chehab8aa153f2019-01-29 14:00:15 -0200570 fmt = &formats[f->index];
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300571 f->pixelformat = fmt->fourcc;
572 return 0;
573 }
574
575 /* Format not found */
576 return -EINVAL;
577}
578
579static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
580 struct v4l2_fmtdesc *f)
581{
582 return enum_fmt(f, MEM2MEM_CAPTURE);
583}
584
585static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
586 struct v4l2_fmtdesc *f)
587{
588 return enum_fmt(f, MEM2MEM_OUTPUT);
589}
590
Hans Verkuil1f923a42014-09-22 09:27:17 -0300591static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300592{
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300593 struct vb2_queue *vq;
Hans Verkuil1f923a42014-09-22 09:27:17 -0300594 struct vim2m_q_data *q_data;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300595
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -0300596 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300597 if (!vq)
598 return -EINVAL;
599
Tomasz Moń9f4161a2012-06-08 04:47:34 -0300600 q_data = get_q_data(ctx, f->type);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300601
602 f->fmt.pix.width = q_data->width;
603 f->fmt.pix.height = q_data->height;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300604 f->fmt.pix.field = V4L2_FIELD_NONE;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300605 f->fmt.pix.pixelformat = q_data->fmt->fourcc;
606 f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
607 f->fmt.pix.sizeimage = q_data->sizeimage;
Hans Verkuil47556ff2012-07-18 11:33:22 -0300608 f->fmt.pix.colorspace = ctx->colorspace;
Hans Verkuil9f8b3332016-07-18 08:00:20 -0300609 f->fmt.pix.xfer_func = ctx->xfer_func;
610 f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
611 f->fmt.pix.quantization = ctx->quant;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300612
613 return 0;
614}
615
616static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
617 struct v4l2_format *f)
618{
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300619 return vidioc_g_fmt(file2ctx(file), f);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300620}
621
622static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
623 struct v4l2_format *f)
624{
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300625 return vidioc_g_fmt(file2ctx(file), f);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300626}
627
Hans Verkuil1f923a42014-09-22 09:27:17 -0300628static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300629{
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300630 /* V4L2 specification suggests the driver corrects the format struct
631 * if any of the dimensions is unsupported */
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300632 if (f->fmt.pix.height < MIN_H)
633 f->fmt.pix.height = MIN_H;
634 else if (f->fmt.pix.height > MAX_H)
635 f->fmt.pix.height = MAX_H;
636
637 if (f->fmt.pix.width < MIN_W)
638 f->fmt.pix.width = MIN_W;
639 else if (f->fmt.pix.width > MAX_W)
640 f->fmt.pix.width = MAX_W;
641
642 f->fmt.pix.width &= ~DIM_ALIGN_MASK;
643 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
644 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
Hans Verkuil5c3112b2014-03-10 10:58:29 -0300645 f->fmt.pix.field = V4L2_FIELD_NONE;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300646
647 return 0;
648}
649
650static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
651 struct v4l2_format *f)
652{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300653 struct vim2m_fmt *fmt;
654 struct vim2m_ctx *ctx = file2ctx(file);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300655
656 fmt = find_format(f);
Hans Verkuil4e8ec0a2014-03-10 10:58:24 -0300657 if (!fmt) {
658 f->fmt.pix.pixelformat = formats[0].fourcc;
659 fmt = find_format(f);
660 }
Hans Verkuil47556ff2012-07-18 11:33:22 -0300661 f->fmt.pix.colorspace = ctx->colorspace;
Hans Verkuil9f8b3332016-07-18 08:00:20 -0300662 f->fmt.pix.xfer_func = ctx->xfer_func;
663 f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
664 f->fmt.pix.quantization = ctx->quant;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300665
666 return vidioc_try_fmt(f, fmt);
667}
668
669static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
670 struct v4l2_format *f)
671{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300672 struct vim2m_fmt *fmt;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300673
674 fmt = find_format(f);
Hans Verkuil4e8ec0a2014-03-10 10:58:24 -0300675 if (!fmt) {
676 f->fmt.pix.pixelformat = formats[0].fourcc;
677 fmt = find_format(f);
678 }
Hans Verkuil47556ff2012-07-18 11:33:22 -0300679 if (!f->fmt.pix.colorspace)
680 f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300681
682 return vidioc_try_fmt(f, fmt);
683}
684
Hans Verkuil1f923a42014-09-22 09:27:17 -0300685static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300686{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300687 struct vim2m_q_data *q_data;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300688 struct vb2_queue *vq;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300689
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -0300690 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300691 if (!vq)
692 return -EINVAL;
693
Tomasz Moń9f4161a2012-06-08 04:47:34 -0300694 q_data = get_q_data(ctx, f->type);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300695 if (!q_data)
696 return -EINVAL;
697
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300698 if (vb2_is_busy(vq)) {
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300699 v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
Marek Szyprowski07e80302010-12-20 14:39:25 -0300700 return -EBUSY;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300701 }
702
703 q_data->fmt = find_format(f);
704 q_data->width = f->fmt.pix.width;
705 q_data->height = f->fmt.pix.height;
706 q_data->sizeimage = q_data->width * q_data->height
707 * q_data->fmt->depth >> 3;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300708
709 dprintk(ctx->dev,
710 "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
711 f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
712
Marek Szyprowski07e80302010-12-20 14:39:25 -0300713 return 0;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300714}
715
716static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
717 struct v4l2_format *f)
718{
719 int ret;
720
721 ret = vidioc_try_fmt_vid_cap(file, priv, f);
722 if (ret)
723 return ret;
724
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300725 return vidioc_s_fmt(file2ctx(file), f);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300726}
727
728static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
729 struct v4l2_format *f)
730{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300731 struct vim2m_ctx *ctx = file2ctx(file);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300732 int ret;
733
734 ret = vidioc_try_fmt_vid_out(file, priv, f);
735 if (ret)
736 return ret;
737
Hans Verkuil47556ff2012-07-18 11:33:22 -0300738 ret = vidioc_s_fmt(file2ctx(file), f);
Hans Verkuil9f8b3332016-07-18 08:00:20 -0300739 if (!ret) {
Hans Verkuil47556ff2012-07-18 11:33:22 -0300740 ctx->colorspace = f->fmt.pix.colorspace;
Hans Verkuil9f8b3332016-07-18 08:00:20 -0300741 ctx->xfer_func = f->fmt.pix.xfer_func;
742 ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
743 ctx->quant = f->fmt.pix.quantization;
744 }
Hans Verkuil47556ff2012-07-18 11:33:22 -0300745 return ret;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300746}
747
Hans Verkuil1f923a42014-09-22 09:27:17 -0300748static int vim2m_s_ctrl(struct v4l2_ctrl *ctrl)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300749{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300750 struct vim2m_ctx *ctx =
751 container_of(ctrl->handler, struct vim2m_ctx, hdl);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300752
753 switch (ctrl->id) {
Tomasz Moń80072872012-06-12 06:43:49 -0300754 case V4L2_CID_HFLIP:
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300755 if (ctrl->val)
Tomasz Moń80072872012-06-12 06:43:49 -0300756 ctx->mode |= MEM2MEM_HFLIP;
757 else
758 ctx->mode &= ~MEM2MEM_HFLIP;
759 break;
760
761 case V4L2_CID_VFLIP:
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300762 if (ctrl->val)
Tomasz Moń80072872012-06-12 06:43:49 -0300763 ctx->mode |= MEM2MEM_VFLIP;
764 else
765 ctx->mode &= ~MEM2MEM_VFLIP;
766 break;
767
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300768 case V4L2_CID_TRANS_TIME_MSEC:
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300769 ctx->transtime = ctrl->val;
Mauro Carvalho Chehabf0ef0222019-01-29 14:00:17 -0200770 if (ctx->transtime < 1)
771 ctx->transtime = 1;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300772 break;
773
774 case V4L2_CID_TRANS_NUM_BUFS:
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300775 ctx->translen = ctrl->val;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300776 break;
777
778 default:
779 v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
780 return -EINVAL;
781 }
782
783 return 0;
784}
785
Hans Verkuil1f923a42014-09-22 09:27:17 -0300786static const struct v4l2_ctrl_ops vim2m_ctrl_ops = {
787 .s_ctrl = vim2m_s_ctrl,
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300788};
789
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300790
Hans Verkuil1f923a42014-09-22 09:27:17 -0300791static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300792 .vidioc_querycap = vidioc_querycap,
793
794 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
795 .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
796 .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
797 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
798
799 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
800 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
801 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
802 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
803
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -0300804 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
805 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
806 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
807 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
Hans Verkuil7bcff1c2015-06-05 11:28:52 -0300808 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
809 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
Hans Verkuilf5294f42014-11-18 09:51:07 -0300810 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300811
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -0300812 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
813 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300814
Hans Verkuil97a3c902012-07-18 10:54:59 -0300815 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
816 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300817};
818
819
820/*
821 * Queue operations
822 */
823
Hans Verkuil1f923a42014-09-22 09:27:17 -0300824static int vim2m_queue_setup(struct vb2_queue *vq,
Guennadi Liakhovetskifc714e702011-08-24 10:30:21 -0300825 unsigned int *nbuffers, unsigned int *nplanes,
Hans Verkuil36c0f8b2016-04-15 09:15:05 -0300826 unsigned int sizes[], struct device *alloc_devs[])
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300827{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300828 struct vim2m_ctx *ctx = vb2_get_drv_priv(vq);
829 struct vim2m_q_data *q_data;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300830 unsigned int size, count = *nbuffers;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300831
Tomasz Moń9f4161a2012-06-08 04:47:34 -0300832 q_data = get_q_data(ctx, vq->type);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300833
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300834 size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300835
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300836 while (size * count > MEM2MEM_VID_MEM_LIMIT)
837 (count)--;
Hans Verkuildf9ecb0c2015-10-28 00:50:37 -0200838 *nbuffers = count;
839
840 if (*nplanes)
841 return sizes[0] < size ? -EINVAL : 0;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300842
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300843 *nplanes = 1;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300844 sizes[0] = size;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300845
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300846 dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300847
848 return 0;
849}
850
Hans Verkuilab7afaf32019-01-16 10:01:14 -0200851static int vim2m_buf_out_validate(struct vb2_buffer *vb)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300852{
Junghak Sung2d700712015-09-22 10:30:30 -0300853 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuil1f923a42014-09-22 09:27:17 -0300854 struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
Hans Verkuilab7afaf32019-01-16 10:01:14 -0200855
856 if (vbuf->field == V4L2_FIELD_ANY)
857 vbuf->field = V4L2_FIELD_NONE;
858 if (vbuf->field != V4L2_FIELD_NONE) {
859 dprintk(ctx->dev, "%s field isn't supported\n", __func__);
860 return -EINVAL;
861 }
862
863 return 0;
864}
865
866static int vim2m_buf_prepare(struct vb2_buffer *vb)
867{
868 struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
Hans Verkuil1f923a42014-09-22 09:27:17 -0300869 struct vim2m_q_data *q_data;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300870
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300871 dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300872
Tomasz Moń9f4161a2012-06-08 04:47:34 -0300873 q_data = get_q_data(ctx, vb->vb2_queue->type);
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300874 if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
875 dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
876 __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300877 return -EINVAL;
878 }
879
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300880 vb2_set_plane_payload(vb, 0, q_data->sizeimage);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300881
882 return 0;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300883}
884
Hans Verkuil1f923a42014-09-22 09:27:17 -0300885static void vim2m_buf_queue(struct vb2_buffer *vb)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300886{
Junghak Sung2d700712015-09-22 10:30:30 -0300887 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
Hans Verkuil1f923a42014-09-22 09:27:17 -0300888 struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
Hans Verkuilca5f5fd2014-03-10 10:58:28 -0300889
Junghak Sung2d700712015-09-22 10:30:30 -0300890 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
Michael Olbrich0f910bf2011-07-12 09:46:44 -0300891}
892
Hans Verkuil1f923a42014-09-22 09:27:17 -0300893static int vim2m_start_streaming(struct vb2_queue *q, unsigned count)
Hans Verkuilca5f5fd2014-03-10 10:58:28 -0300894{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300895 struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
896 struct vim2m_q_data *q_data = get_q_data(ctx, q->type);
Hans Verkuilca5f5fd2014-03-10 10:58:28 -0300897
898 q_data->sequence = 0;
899 return 0;
900}
901
Hans Verkuil1f923a42014-09-22 09:27:17 -0300902static void vim2m_stop_streaming(struct vb2_queue *q)
Hans Verkuila7736322014-03-10 10:58:27 -0300903{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300904 struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
Junghak Sung2d700712015-09-22 10:30:30 -0300905 struct vb2_v4l2_buffer *vbuf;
Hans Verkuila7736322014-03-10 10:58:27 -0300906 unsigned long flags;
907
Mauro Carvalho Chehaba8566d72019-02-18 10:29:31 -0500908 cancel_delayed_work_sync(&ctx->work_run);
Hans Verkuil240809e2019-01-11 07:07:25 -0500909
Hans Verkuila7736322014-03-10 10:58:27 -0300910 for (;;) {
911 if (V4L2_TYPE_IS_OUTPUT(q->type))
Junghak Sung2d700712015-09-22 10:30:30 -0300912 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
Hans Verkuila7736322014-03-10 10:58:27 -0300913 else
Junghak Sung2d700712015-09-22 10:30:30 -0300914 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
915 if (vbuf == NULL)
Hans Verkuile37559b2014-04-17 02:47:21 -0300916 return;
Hans Verkuil86b93b22018-05-21 04:54:57 -0400917 v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
918 &ctx->hdl);
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200919 spin_lock_irqsave(&ctx->irqlock, flags);
Junghak Sung2d700712015-09-22 10:30:30 -0300920 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200921 spin_unlock_irqrestore(&ctx->irqlock, flags);
Hans Verkuila7736322014-03-10 10:58:27 -0300922 }
Hans Verkuila7736322014-03-10 10:58:27 -0300923}
924
Hans Verkuil86b93b22018-05-21 04:54:57 -0400925static void vim2m_buf_request_complete(struct vb2_buffer *vb)
926{
927 struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
928
929 v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
930}
931
Julia Lawallb7b361f2016-09-08 20:59:10 -0300932static const struct vb2_ops vim2m_qops = {
Hans Verkuil1f923a42014-09-22 09:27:17 -0300933 .queue_setup = vim2m_queue_setup,
Hans Verkuilab7afaf32019-01-16 10:01:14 -0200934 .buf_out_validate = vim2m_buf_out_validate,
Hans Verkuil1f923a42014-09-22 09:27:17 -0300935 .buf_prepare = vim2m_buf_prepare,
936 .buf_queue = vim2m_buf_queue,
937 .start_streaming = vim2m_start_streaming,
938 .stop_streaming = vim2m_stop_streaming,
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -0300939 .wait_prepare = vb2_ops_wait_prepare,
940 .wait_finish = vb2_ops_wait_finish,
Hans Verkuil86b93b22018-05-21 04:54:57 -0400941 .buf_request_complete = vim2m_buf_request_complete,
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300942};
943
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300944static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300945{
Hans Verkuil1f923a42014-09-22 09:27:17 -0300946 struct vim2m_ctx *ctx = priv;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300947 int ret;
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300948
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300949 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
Hans Verkuil782f36c2014-03-10 10:58:26 -0300950 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300951 src_vq->drv_priv = ctx;
952 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
Hans Verkuil1f923a42014-09-22 09:27:17 -0300953 src_vq->ops = &vim2m_qops;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300954 src_vq->mem_ops = &vb2_vmalloc_memops;
Sakari Ailusade48682014-02-25 19:12:19 -0300955 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200956 src_vq->lock = &ctx->vb_mutex;
Hans Verkuile5079cf2018-08-23 10:18:35 -0400957 src_vq->supports_requests = true;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300958
959 ret = vb2_queue_init(src_vq);
960 if (ret)
961 return ret;
962
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300963 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Hans Verkuil782f36c2014-03-10 10:58:26 -0300964 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300965 dst_vq->drv_priv = ctx;
966 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
Hans Verkuil1f923a42014-09-22 09:27:17 -0300967 dst_vq->ops = &vim2m_qops;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300968 dst_vq->mem_ops = &vb2_vmalloc_memops;
Sakari Ailusade48682014-02-25 19:12:19 -0300969 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -0200970 dst_vq->lock = &ctx->vb_mutex;
Marek Szyprowskid80ee382011-01-12 06:50:55 -0300971
972 return vb2_queue_init(dst_vq);
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300973}
974
Mauro Carvalho Chehabf0ef0222019-01-29 14:00:17 -0200975static struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = {
Hans Verkuil1f923a42014-09-22 09:27:17 -0300976 .ops = &vim2m_ctrl_ops,
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300977 .id = V4L2_CID_TRANS_TIME_MSEC,
978 .name = "Transaction Time (msec)",
979 .type = V4L2_CTRL_TYPE_INTEGER,
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300980 .min = 1,
981 .max = 10001,
Hans Verkuil43405832014-03-10 10:58:23 -0300982 .step = 1,
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300983};
984
Hans Verkuil1f923a42014-09-22 09:27:17 -0300985static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs = {
986 .ops = &vim2m_ctrl_ops,
Hans Verkuild3dd59c2012-07-18 10:35:37 -0300987 .id = V4L2_CID_TRANS_NUM_BUFS,
988 .name = "Buffers Per Transaction",
989 .type = V4L2_CTRL_TYPE_INTEGER,
990 .def = 1,
991 .min = 1,
992 .max = MEM2MEM_DEF_NUM_BUFS,
993 .step = 1,
994};
995
Pawel Osciak96d8eab2010-04-23 05:38:38 -0300996/*
997 * File operations
998 */
Hans Verkuil1f923a42014-09-22 09:27:17 -0300999static int vim2m_open(struct file *file)
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001000{
Hans Verkuil1f923a42014-09-22 09:27:17 -03001001 struct vim2m_dev *dev = video_drvdata(file);
1002 struct vim2m_ctx *ctx = NULL;
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001003 struct v4l2_ctrl_handler *hdl;
Hans Verkuilf4694032012-07-31 03:51:25 -03001004 int rc = 0;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001005
Hans Verkuilf4694032012-07-31 03:51:25 -03001006 if (mutex_lock_interruptible(&dev->dev_mutex))
1007 return -ERESTARTSYS;
Sachin Kamat56ed2212012-09-24 02:17:46 -03001008 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Hans Verkuilf4694032012-07-31 03:51:25 -03001009 if (!ctx) {
1010 rc = -ENOMEM;
1011 goto open_unlock;
1012 }
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001013
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001014 v4l2_fh_init(&ctx->fh, video_devdata(file));
1015 file->private_data = &ctx->fh;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001016 ctx->dev = dev;
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001017 hdl = &ctx->hdl;
1018 v4l2_ctrl_handler_init(hdl, 4);
Hans Verkuil1f923a42014-09-22 09:27:17 -03001019 v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
1020 v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
Mauro Carvalho Chehabf0ef0222019-01-29 14:00:17 -02001021
1022 vim2m_ctrl_trans_time_msec.def = default_transtime;
Hans Verkuil1f923a42014-09-22 09:27:17 -03001023 v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
1024 v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL);
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001025 if (hdl->error) {
Dan Carpentera7bd7752012-08-14 02:58:56 -03001026 rc = hdl->error;
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001027 v4l2_ctrl_handler_free(hdl);
Santosh Kumar Singh7c13a4d2016-12-19 14:12:46 -02001028 kfree(ctx);
Dan Carpentera7bd7752012-08-14 02:58:56 -03001029 goto open_unlock;
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001030 }
1031 ctx->fh.ctrl_handler = hdl;
1032 v4l2_ctrl_handler_setup(hdl);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001033
Tomasz Moń9f4161a2012-06-08 04:47:34 -03001034 ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
Hans Verkuil47556ff2012-07-18 11:33:22 -03001035 ctx->q_data[V4L2_M2M_SRC].width = 640;
1036 ctx->q_data[V4L2_M2M_SRC].height = 480;
1037 ctx->q_data[V4L2_M2M_SRC].sizeimage =
1038 ctx->q_data[V4L2_M2M_SRC].width *
1039 ctx->q_data[V4L2_M2M_SRC].height *
1040 (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3);
1041 ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
1042 ctx->colorspace = V4L2_COLORSPACE_REC709;
Tomasz Moń9f4161a2012-06-08 04:47:34 -03001043
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -03001044 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
Marek Szyprowskid80ee382011-01-12 06:50:55 -03001045
Mauro Carvalho Chehabb3e64e52019-01-29 14:00:16 -02001046 mutex_init(&ctx->vb_mutex);
1047 spin_lock_init(&ctx->irqlock);
1048 INIT_DELAYED_WORK(&ctx->work_run, device_work);
1049
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -03001050 if (IS_ERR(ctx->fh.m2m_ctx)) {
1051 rc = PTR_ERR(ctx->fh.m2m_ctx);
Dan Carpenter16ee9bb12010-05-05 02:58:57 -03001052
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001053 v4l2_ctrl_handler_free(hdl);
Santosh Kumar Singh7c13a4d2016-12-19 14:12:46 -02001054 v4l2_fh_exit(&ctx->fh);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001055 kfree(ctx);
Hans Verkuilf4694032012-07-31 03:51:25 -03001056 goto open_unlock;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001057 }
1058
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001059 v4l2_fh_add(&ctx->fh);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001060 atomic_inc(&dev->num_inst);
1061
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -03001062 dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
1063 ctx, ctx->fh.m2m_ctx);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001064
Hans Verkuilf4694032012-07-31 03:51:25 -03001065open_unlock:
1066 mutex_unlock(&dev->dev_mutex);
Dan Carpentera7bd7752012-08-14 02:58:56 -03001067 return rc;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001068}
1069
Hans Verkuil1f923a42014-09-22 09:27:17 -03001070static int vim2m_release(struct file *file)
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001071{
Hans Verkuil1f923a42014-09-22 09:27:17 -03001072 struct vim2m_dev *dev = video_drvdata(file);
1073 struct vim2m_ctx *ctx = file2ctx(file);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001074
1075 dprintk(dev, "Releasing instance %p\n", ctx);
1076
Hans Verkuild3dd59c2012-07-18 10:35:37 -03001077 v4l2_fh_del(&ctx->fh);
1078 v4l2_fh_exit(&ctx->fh);
1079 v4l2_ctrl_handler_free(&ctx->hdl);
Hans Verkuilf4694032012-07-31 03:51:25 -03001080 mutex_lock(&dev->dev_mutex);
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -03001081 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
Hans Verkuilf4694032012-07-31 03:51:25 -03001082 mutex_unlock(&dev->dev_mutex);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001083 kfree(ctx);
1084
1085 atomic_dec(&dev->num_inst);
1086
1087 return 0;
1088}
1089
Hans Verkuil1f923a42014-09-22 09:27:17 -03001090static const struct v4l2_file_operations vim2m_fops = {
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001091 .owner = THIS_MODULE,
Hans Verkuil1f923a42014-09-22 09:27:17 -03001092 .open = vim2m_open,
1093 .release = vim2m_release,
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -03001094 .poll = v4l2_m2m_fop_poll,
Marek Szyprowski07e80302010-12-20 14:39:25 -03001095 .unlocked_ioctl = video_ioctl2,
Sylwester Nawrocki20702eb2013-08-25 17:27:45 -03001096 .mmap = v4l2_m2m_fop_mmap,
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001097};
1098
Bhumika Goyal53031352017-08-26 08:57:26 -04001099static const struct video_device vim2m_videodev = {
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001100 .name = MEM2MEM_NAME,
Hans Verkuil954f3402012-09-05 06:05:50 -03001101 .vfl_dir = VFL_DIR_M2M,
Hans Verkuil1f923a42014-09-22 09:27:17 -03001102 .fops = &vim2m_fops,
1103 .ioctl_ops = &vim2m_ioctl_ops,
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001104 .minor = -1,
Hans Verkuil09365422015-03-09 13:33:56 -03001105 .release = video_device_release_empty,
Hans Verkuil47fc65fa2018-11-15 03:16:22 -05001106 .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001107};
1108
Julia Lawall86ab0b12017-08-06 04:25:19 -04001109static const struct v4l2_m2m_ops m2m_ops = {
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001110 .device_run = device_run,
1111 .job_ready = job_ready,
1112 .job_abort = job_abort,
1113};
1114
Hans Verkuil86b93b22018-05-21 04:54:57 -04001115static const struct media_device_ops m2m_media_ops = {
1116 .req_validate = vb2_request_validate,
Ezequiel Garciaef86eaf2018-10-18 14:54:29 -04001117 .req_queue = v4l2_m2m_request_queue,
Hans Verkuil86b93b22018-05-21 04:54:57 -04001118};
1119
Hans Verkuil1f923a42014-09-22 09:27:17 -03001120static int vim2m_probe(struct platform_device *pdev)
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001121{
Hans Verkuil1f923a42014-09-22 09:27:17 -03001122 struct vim2m_dev *dev;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001123 struct video_device *vfd;
1124 int ret;
1125
Sachin Kamat38a79962012-09-24 02:17:48 -03001126 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001127 if (!dev)
1128 return -ENOMEM;
1129
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001130 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
1131 if (ret)
Sachin Kamat38a79962012-09-24 02:17:48 -03001132 return ret;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001133
1134 atomic_set(&dev->num_inst, 0);
1135 mutex_init(&dev->dev_mutex);
1136
Hans Verkuil09365422015-03-09 13:33:56 -03001137 dev->vfd = vim2m_videodev;
1138 vfd = &dev->vfd;
Marek Szyprowski07e80302010-12-20 14:39:25 -03001139 vfd->lock = &dev->dev_mutex;
Hans Verkuil8f484d82013-06-27 02:44:04 -03001140 vfd->v4l2_dev = &dev->v4l2_dev;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001141
1142 ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
1143 if (ret) {
1144 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
Hans Verkuile35f7022018-07-02 11:36:06 -04001145 goto unreg_v4l2;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001146 }
1147
1148 video_set_drvdata(vfd, dev);
Hans Verkuil8f484d82013-06-27 02:44:04 -03001149 v4l2_info(&dev->v4l2_dev,
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001150 "Device registered as /dev/video%d\n", vfd->num);
1151
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001152 platform_set_drvdata(pdev, dev);
1153
1154 dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
1155 if (IS_ERR(dev->m2m_dev)) {
1156 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
1157 ret = PTR_ERR(dev->m2m_dev);
Hans Verkuile35f7022018-07-02 11:36:06 -04001158 goto unreg_dev;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001159 }
1160
Hans Verkuile35f7022018-07-02 11:36:06 -04001161#ifdef CONFIG_MEDIA_CONTROLLER
1162 dev->mdev.dev = &pdev->dev;
Mauro Carvalho Chehabc0decac2018-09-10 08:19:14 -04001163 strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model));
Hans Verkuil281ae392019-01-30 08:39:17 -05001164 strscpy(dev->mdev.bus_info, "platform:vim2m",
1165 sizeof(dev->mdev.bus_info));
Hans Verkuile35f7022018-07-02 11:36:06 -04001166 media_device_init(&dev->mdev);
Hans Verkuil86b93b22018-05-21 04:54:57 -04001167 dev->mdev.ops = &m2m_media_ops;
Hans Verkuile35f7022018-07-02 11:36:06 -04001168 dev->v4l2_dev.mdev = &dev->mdev;
1169
1170 ret = v4l2_m2m_register_media_controller(dev->m2m_dev,
1171 vfd, MEDIA_ENT_F_PROC_VIDEO_SCALER);
1172 if (ret) {
1173 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
1174 goto unreg_m2m;
1175 }
1176
1177 ret = media_device_register(&dev->mdev);
1178 if (ret) {
1179 v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
1180 goto unreg_m2m_mc;
1181 }
1182#endif
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001183 return 0;
1184
Hans Verkuile35f7022018-07-02 11:36:06 -04001185#ifdef CONFIG_MEDIA_CONTROLLER
1186unreg_m2m_mc:
1187 v4l2_m2m_unregister_media_controller(dev->m2m_dev);
1188unreg_m2m:
Sachin Kamatb7e13ef2012-09-24 02:17:45 -03001189 v4l2_m2m_release(dev->m2m_dev);
Hans Verkuile35f7022018-07-02 11:36:06 -04001190#endif
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001191unreg_dev:
Hans Verkuile35f7022018-07-02 11:36:06 -04001192 video_unregister_device(&dev->vfd);
1193unreg_v4l2:
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001194 v4l2_device_unregister(&dev->v4l2_dev);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001195
1196 return ret;
1197}
1198
Hans Verkuil1f923a42014-09-22 09:27:17 -03001199static int vim2m_remove(struct platform_device *pdev)
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001200{
Hans Verkuil1f923a42014-09-22 09:27:17 -03001201 struct vim2m_dev *dev = platform_get_drvdata(pdev);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001202
Hans Verkuil1f923a42014-09-22 09:27:17 -03001203 v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
Hans Verkuile35f7022018-07-02 11:36:06 -04001204
1205#ifdef CONFIG_MEDIA_CONTROLLER
1206 media_device_unregister(&dev->mdev);
1207 v4l2_m2m_unregister_media_controller(dev->m2m_dev);
1208 media_device_cleanup(&dev->mdev);
1209#endif
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001210 v4l2_m2m_release(dev->m2m_dev);
Hans Verkuil09365422015-03-09 13:33:56 -03001211 video_unregister_device(&dev->vfd);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001212 v4l2_device_unregister(&dev->v4l2_dev);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001213
1214 return 0;
1215}
1216
Hans Verkuil1f923a42014-09-22 09:27:17 -03001217static struct platform_driver vim2m_pdrv = {
1218 .probe = vim2m_probe,
1219 .remove = vim2m_remove,
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001220 .driver = {
1221 .name = MEM2MEM_NAME,
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001222 },
1223};
1224
Hans Verkuil1f923a42014-09-22 09:27:17 -03001225static void __exit vim2m_exit(void)
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001226{
Hans Verkuil1f923a42014-09-22 09:27:17 -03001227 platform_driver_unregister(&vim2m_pdrv);
1228 platform_device_unregister(&vim2m_pdev);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001229}
1230
Hans Verkuil1f923a42014-09-22 09:27:17 -03001231static int __init vim2m_init(void)
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001232{
1233 int ret;
1234
Hans Verkuil1f923a42014-09-22 09:27:17 -03001235 ret = platform_device_register(&vim2m_pdev);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001236 if (ret)
1237 return ret;
1238
Hans Verkuil1f923a42014-09-22 09:27:17 -03001239 ret = platform_driver_register(&vim2m_pdrv);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001240 if (ret)
Hans Verkuil1f923a42014-09-22 09:27:17 -03001241 platform_device_unregister(&vim2m_pdev);
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001242
Niklas Söderlundb20b51f2015-12-25 15:25:16 -02001243 return ret;
Pawel Osciak96d8eab2010-04-23 05:38:38 -03001244}
1245
Hans Verkuil1f923a42014-09-22 09:27:17 -03001246module_init(vim2m_init);
1247module_exit(vim2m_exit);