blob: bc580fbe18fac9d9567f491f963b6ca4d9725d36 [file] [log] [blame]
Pawel Osciak7f986392010-04-23 05:38:37 -03001/*
2 * Memory-to-memory device framework for Video for Linux 2 and videobuf.
3 *
4 * Helper functions for devices that use videobuf buffers for both their
5 * source and destination.
6 *
7 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
Pawel Osciak95072082011-03-13 15:23:32 -03008 * Pawel Osciak, <pawel@osciak.com>
Pawel Osciak7f986392010-04-23 05:38:37 -03009 * Marek Szyprowski, <m.szyprowski@samsung.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16#include <linux/module.h>
17#include <linux/sched.h>
18#include <linux/slab.h>
19
Junghak Sungc1399902015-09-22 10:30:29 -030020#include <media/videobuf2-v4l2.h>
Pawel Osciak7f986392010-04-23 05:38:37 -030021#include <media/v4l2-mem2mem.h>
Hans Verkuil08eb8512012-07-18 10:53:04 -030022#include <media/v4l2-dev.h>
23#include <media/v4l2-fh.h>
24#include <media/v4l2-event.h>
Pawel Osciak7f986392010-04-23 05:38:37 -030025
26MODULE_DESCRIPTION("Mem to mem device framework for videobuf");
Pawel Osciak95072082011-03-13 15:23:32 -030027MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
Pawel Osciak7f986392010-04-23 05:38:37 -030028MODULE_LICENSE("GPL");
29
30static bool debug;
31module_param(debug, bool, 0644);
32
33#define dprintk(fmt, arg...) \
34 do { \
35 if (debug) \
36 printk(KERN_DEBUG "%s: " fmt, __func__, ## arg);\
37 } while (0)
38
39
40/* Instance is already queued on the job_queue */
41#define TRANS_QUEUED (1 << 0)
42/* Instance is currently running in hardware */
43#define TRANS_RUNNING (1 << 1)
Shaik Ameer Basha2ad53892013-09-20 03:26:18 -030044/* Instance is currently aborting */
45#define TRANS_ABORT (1 << 2)
Pawel Osciak7f986392010-04-23 05:38:37 -030046
47
48/* Offset base for buffers on the destination queue - used to distinguish
49 * between source and destination buffers when mmapping - they receive the same
50 * offsets but for different queues */
51#define DST_QUEUE_OFF_BASE (1 << 30)
52
53
54/**
55 * struct v4l2_m2m_dev - per-device context
56 * @curr_ctx: currently running instance
57 * @job_queue: instances queued to run
58 * @job_spinlock: protects job_queue
59 * @m2m_ops: driver callbacks
60 */
61struct v4l2_m2m_dev {
62 struct v4l2_m2m_ctx *curr_ctx;
63
64 struct list_head job_queue;
65 spinlock_t job_spinlock;
66
Guennadi Liakhovetskib1252eb2012-09-11 06:32:17 -030067 const struct v4l2_m2m_ops *m2m_ops;
Pawel Osciak7f986392010-04-23 05:38:37 -030068};
69
70static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
71 enum v4l2_buf_type type)
72{
Marek Szyprowski908a0d72011-01-12 06:50:24 -030073 if (V4L2_TYPE_IS_OUTPUT(type))
Pawel Osciak7f986392010-04-23 05:38:37 -030074 return &m2m_ctx->out_q_ctx;
Marek Szyprowski908a0d72011-01-12 06:50:24 -030075 else
76 return &m2m_ctx->cap_q_ctx;
Pawel Osciak7f986392010-04-23 05:38:37 -030077}
78
Marek Szyprowski908a0d72011-01-12 06:50:24 -030079struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
Pawel Osciak7f986392010-04-23 05:38:37 -030080 enum v4l2_buf_type type)
81{
82 struct v4l2_m2m_queue_ctx *q_ctx;
83
84 q_ctx = get_queue_ctx(m2m_ctx, type);
85 if (!q_ctx)
86 return NULL;
87
88 return &q_ctx->q;
89}
90EXPORT_SYMBOL(v4l2_m2m_get_vq);
91
Marek Szyprowski908a0d72011-01-12 06:50:24 -030092void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx)
Pawel Osciak7f986392010-04-23 05:38:37 -030093{
Philipp Zabeld5451c12015-03-11 12:57:50 -030094 struct v4l2_m2m_buffer *b;
Pawel Osciak7f986392010-04-23 05:38:37 -030095 unsigned long flags;
96
Marek Szyprowski908a0d72011-01-12 06:50:24 -030097 spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
Pawel Osciak7f986392010-04-23 05:38:37 -030098
Andrzej Pietrasiewicza6bd62be2011-08-25 07:21:21 -030099 if (list_empty(&q_ctx->rdy_queue)) {
100 spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
101 return NULL;
102 }
Pawel Osciak7f986392010-04-23 05:38:37 -0300103
Sascha Hauerc392e9e2012-08-31 09:18:03 -0300104 b = list_first_entry(&q_ctx->rdy_queue, struct v4l2_m2m_buffer, list);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300105 spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
106 return &b->vb;
Pawel Osciak7f986392010-04-23 05:38:37 -0300107}
108EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf);
109
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300110void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx)
Pawel Osciak7f986392010-04-23 05:38:37 -0300111{
Philipp Zabeld5451c12015-03-11 12:57:50 -0300112 struct v4l2_m2m_buffer *b;
Pawel Osciak7f986392010-04-23 05:38:37 -0300113 unsigned long flags;
114
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300115 spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
Andrzej Pietrasiewicza6bd62be2011-08-25 07:21:21 -0300116 if (list_empty(&q_ctx->rdy_queue)) {
117 spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
118 return NULL;
Pawel Osciak7f986392010-04-23 05:38:37 -0300119 }
Sascha Hauerc392e9e2012-08-31 09:18:03 -0300120 b = list_first_entry(&q_ctx->rdy_queue, struct v4l2_m2m_buffer, list);
Andrzej Pietrasiewicza6bd62be2011-08-25 07:21:21 -0300121 list_del(&b->list);
122 q_ctx->num_rdy--;
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300123 spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
Pawel Osciak7f986392010-04-23 05:38:37 -0300124
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300125 return &b->vb;
Pawel Osciak7f986392010-04-23 05:38:37 -0300126}
127EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove);
128
Stanimir Varbanovd4987562017-06-15 13:31:42 -0300129void v4l2_m2m_buf_remove_by_buf(struct v4l2_m2m_queue_ctx *q_ctx,
130 struct vb2_v4l2_buffer *vbuf)
131{
132 struct v4l2_m2m_buffer *b;
133 unsigned long flags;
134
135 spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
136 b = container_of(vbuf, struct v4l2_m2m_buffer, vb);
137 list_del(&b->list);
138 q_ctx->num_rdy--;
139 spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
140}
141EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove_by_buf);
142
143struct vb2_v4l2_buffer *
144v4l2_m2m_buf_remove_by_idx(struct v4l2_m2m_queue_ctx *q_ctx, unsigned int idx)
145
146{
147 struct v4l2_m2m_buffer *b, *tmp;
148 struct vb2_v4l2_buffer *ret = NULL;
149 unsigned long flags;
150
151 spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
152 list_for_each_entry_safe(b, tmp, &q_ctx->rdy_queue, list) {
153 if (b->vb.vb2_buf.index == idx) {
154 list_del(&b->list);
155 q_ctx->num_rdy--;
156 ret = &b->vb;
157 break;
158 }
159 }
160 spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
161
162 return ret;
163}
164EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove_by_idx);
165
Pawel Osciak7f986392010-04-23 05:38:37 -0300166/*
167 * Scheduling handlers
168 */
169
Pawel Osciak7f986392010-04-23 05:38:37 -0300170void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev)
171{
172 unsigned long flags;
173 void *ret = NULL;
174
175 spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
176 if (m2m_dev->curr_ctx)
177 ret = m2m_dev->curr_ctx->priv;
178 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
179
180 return ret;
181}
182EXPORT_SYMBOL(v4l2_m2m_get_curr_priv);
183
184/**
185 * v4l2_m2m_try_run() - select next job to perform and run it if possible
Mauro Carvalho Chehabd28b2cf2017-11-29 03:56:18 -0500186 * @m2m_dev: per-device context
Pawel Osciak7f986392010-04-23 05:38:37 -0300187 *
188 * Get next transaction (if present) from the waiting jobs list and run it.
189 */
190static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
191{
192 unsigned long flags;
193
194 spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
195 if (NULL != m2m_dev->curr_ctx) {
196 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
197 dprintk("Another instance is running, won't run now\n");
198 return;
199 }
200
201 if (list_empty(&m2m_dev->job_queue)) {
202 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
203 dprintk("No job pending\n");
204 return;
205 }
206
Sascha Hauerc392e9e2012-08-31 09:18:03 -0300207 m2m_dev->curr_ctx = list_first_entry(&m2m_dev->job_queue,
Pawel Osciak7f986392010-04-23 05:38:37 -0300208 struct v4l2_m2m_ctx, queue);
209 m2m_dev->curr_ctx->job_flags |= TRANS_RUNNING;
210 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
211
212 m2m_dev->m2m_ops->device_run(m2m_dev->curr_ctx->priv);
213}
214
Michael Olbrich1190a412014-07-22 09:36:04 -0300215void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
Pawel Osciak7f986392010-04-23 05:38:37 -0300216{
217 struct v4l2_m2m_dev *m2m_dev;
John Sheub7306272013-05-23 20:41:48 -0300218 unsigned long flags_job, flags_out, flags_cap;
Pawel Osciak7f986392010-04-23 05:38:37 -0300219
220 m2m_dev = m2m_ctx->m2m_dev;
221 dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx);
222
223 if (!m2m_ctx->out_q_ctx.q.streaming
224 || !m2m_ctx->cap_q_ctx.q.streaming) {
225 dprintk("Streaming needs to be on for both queues\n");
226 return;
227 }
228
229 spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job);
Shaik Ameer Basha2ad53892013-09-20 03:26:18 -0300230
231 /* If the context is aborted then don't schedule it */
232 if (m2m_ctx->job_flags & TRANS_ABORT) {
233 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
234 dprintk("Aborted context\n");
235 return;
236 }
237
Pawel Osciak7f986392010-04-23 05:38:37 -0300238 if (m2m_ctx->job_flags & TRANS_QUEUED) {
239 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
240 dprintk("On job queue already\n");
241 return;
242 }
243
John Sheub7306272013-05-23 20:41:48 -0300244 spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
Philipp Zabel33bdd5a2013-06-03 04:23:48 -0300245 if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)
246 && !m2m_ctx->out_q_ctx.buffered) {
John Sheub7306272013-05-23 20:41:48 -0300247 spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock,
248 flags_out);
Pawel Osciak7f986392010-04-23 05:38:37 -0300249 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
250 dprintk("No input buffers available\n");
251 return;
252 }
John Sheub7306272013-05-23 20:41:48 -0300253 spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
Philipp Zabel33bdd5a2013-06-03 04:23:48 -0300254 if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)
255 && !m2m_ctx->cap_q_ctx.buffered) {
John Sheub7306272013-05-23 20:41:48 -0300256 spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock,
257 flags_cap);
258 spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock,
259 flags_out);
Pawel Osciak7f986392010-04-23 05:38:37 -0300260 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
261 dprintk("No output buffers available\n");
262 return;
263 }
John Sheub7306272013-05-23 20:41:48 -0300264 spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
265 spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
Pawel Osciak7f986392010-04-23 05:38:37 -0300266
267 if (m2m_dev->m2m_ops->job_ready
268 && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) {
269 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
270 dprintk("Driver not ready\n");
271 return;
272 }
273
274 list_add_tail(&m2m_ctx->queue, &m2m_dev->job_queue);
275 m2m_ctx->job_flags |= TRANS_QUEUED;
276
277 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
278
279 v4l2_m2m_try_run(m2m_dev);
280}
Michael Olbrich1190a412014-07-22 09:36:04 -0300281EXPORT_SYMBOL_GPL(v4l2_m2m_try_schedule);
Pawel Osciak7f986392010-04-23 05:38:37 -0300282
283/**
Shaik Ameer Bashafea564a2013-08-13 02:58:07 -0300284 * v4l2_m2m_cancel_job() - cancel pending jobs for the context
Mauro Carvalho Chehabd28b2cf2017-11-29 03:56:18 -0500285 * @m2m_ctx: m2m context with jobs to be canceled
Shaik Ameer Bashafea564a2013-08-13 02:58:07 -0300286 *
287 * In case of streamoff or release called on any context,
288 * 1] If the context is currently running, then abort job will be called
289 * 2] If the context is queued, then the context will be removed from
290 * the job_queue
291 */
292static void v4l2_m2m_cancel_job(struct v4l2_m2m_ctx *m2m_ctx)
293{
294 struct v4l2_m2m_dev *m2m_dev;
295 unsigned long flags;
296
297 m2m_dev = m2m_ctx->m2m_dev;
298 spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
Shaik Ameer Basha2ad53892013-09-20 03:26:18 -0300299
300 m2m_ctx->job_flags |= TRANS_ABORT;
Shaik Ameer Bashafea564a2013-08-13 02:58:07 -0300301 if (m2m_ctx->job_flags & TRANS_RUNNING) {
302 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
303 m2m_dev->m2m_ops->job_abort(m2m_ctx->priv);
304 dprintk("m2m_ctx %p running, will wait to complete", m2m_ctx);
305 wait_event(m2m_ctx->finished,
306 !(m2m_ctx->job_flags & TRANS_RUNNING));
307 } else if (m2m_ctx->job_flags & TRANS_QUEUED) {
308 list_del(&m2m_ctx->queue);
309 m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
310 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
311 dprintk("m2m_ctx: %p had been on queue and was removed\n",
312 m2m_ctx);
313 } else {
314 /* Do nothing, was not on queue/running */
315 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
316 }
317}
318
Pawel Osciak7f986392010-04-23 05:38:37 -0300319void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
320 struct v4l2_m2m_ctx *m2m_ctx)
321{
322 unsigned long flags;
323
324 spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
325 if (!m2m_dev->curr_ctx || m2m_dev->curr_ctx != m2m_ctx) {
326 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
327 dprintk("Called by an instance not currently running\n");
328 return;
329 }
330
331 list_del(&m2m_dev->curr_ctx->queue);
332 m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300333 wake_up(&m2m_dev->curr_ctx->finished);
Pawel Osciak7f986392010-04-23 05:38:37 -0300334 m2m_dev->curr_ctx = NULL;
335
336 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
337
338 /* This instance might have more buffers ready, but since we do not
339 * allow more than one job on the job_queue per instance, each has
340 * to be scheduled separately after the previous one finishes. */
341 v4l2_m2m_try_schedule(m2m_ctx);
342 v4l2_m2m_try_run(m2m_dev);
343}
344EXPORT_SYMBOL(v4l2_m2m_job_finish);
345
Pawel Osciak7f986392010-04-23 05:38:37 -0300346int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
347 struct v4l2_requestbuffers *reqbufs)
348{
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300349 struct vb2_queue *vq;
Philipp Zabelc13a5cc2015-07-10 10:49:25 -0300350 int ret;
Pawel Osciak7f986392010-04-23 05:38:37 -0300351
352 vq = v4l2_m2m_get_vq(m2m_ctx, reqbufs->type);
Philipp Zabelc13a5cc2015-07-10 10:49:25 -0300353 ret = vb2_reqbufs(vq, reqbufs);
354 /* If count == 0, then the owner has released all buffers and he
355 is no longer owner of the queue. Otherwise we have an owner. */
356 if (ret == 0)
357 vq->owner = reqbufs->count ? file->private_data : NULL;
358
359 return ret;
Pawel Osciak7f986392010-04-23 05:38:37 -0300360}
361EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs);
362
Pawel Osciak7f986392010-04-23 05:38:37 -0300363int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
364 struct v4l2_buffer *buf)
365{
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300366 struct vb2_queue *vq;
367 int ret = 0;
368 unsigned int i;
Pawel Osciak7f986392010-04-23 05:38:37 -0300369
370 vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300371 ret = vb2_querybuf(vq, buf);
Pawel Osciak7f986392010-04-23 05:38:37 -0300372
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300373 /* Adjust MMAP memory offsets for the CAPTURE queue */
374 if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) {
375 if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) {
376 for (i = 0; i < buf->length; ++i)
377 buf->m.planes[i].m.mem_offset
378 += DST_QUEUE_OFF_BASE;
379 } else {
380 buf->m.offset += DST_QUEUE_OFF_BASE;
381 }
Pawel Osciak7f986392010-04-23 05:38:37 -0300382 }
383
384 return ret;
385}
386EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf);
387
Pawel Osciak7f986392010-04-23 05:38:37 -0300388int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
389 struct v4l2_buffer *buf)
390{
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300391 struct vb2_queue *vq;
Pawel Osciak7f986392010-04-23 05:38:37 -0300392 int ret;
393
394 vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300395 ret = vb2_qbuf(vq, buf);
Pawel Osciak7f986392010-04-23 05:38:37 -0300396 if (!ret)
397 v4l2_m2m_try_schedule(m2m_ctx);
398
399 return ret;
400}
401EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf);
402
Pawel Osciak7f986392010-04-23 05:38:37 -0300403int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
404 struct v4l2_buffer *buf)
405{
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300406 struct vb2_queue *vq;
Pawel Osciak7f986392010-04-23 05:38:37 -0300407
408 vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300409 return vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK);
Pawel Osciak7f986392010-04-23 05:38:37 -0300410}
411EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf);
412
Hans Verkuile68cf472015-06-05 11:28:50 -0300413int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
414 struct v4l2_buffer *buf)
415{
416 struct vb2_queue *vq;
417 int ret;
418
419 vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
420 ret = vb2_prepare_buf(vq, buf);
421 if (!ret)
422 v4l2_m2m_try_schedule(m2m_ctx);
423
424 return ret;
425}
426EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf);
427
Philipp Zabel8b94ca62013-05-21 04:16:28 -0300428int v4l2_m2m_create_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
429 struct v4l2_create_buffers *create)
430{
431 struct vb2_queue *vq;
432
433 vq = v4l2_m2m_get_vq(m2m_ctx, create->format.type);
434 return vb2_create_bufs(vq, create);
435}
436EXPORT_SYMBOL_GPL(v4l2_m2m_create_bufs);
437
Tomasz Stanislawski83ae7c52012-06-14 11:32:24 -0300438int v4l2_m2m_expbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
439 struct v4l2_exportbuffer *eb)
440{
441 struct vb2_queue *vq;
442
443 vq = v4l2_m2m_get_vq(m2m_ctx, eb->type);
444 return vb2_expbuf(vq, eb);
445}
446EXPORT_SYMBOL_GPL(v4l2_m2m_expbuf);
Mauro Carvalho Chehab47816462016-09-08 10:16:27 -0300447
Pawel Osciak7f986392010-04-23 05:38:37 -0300448int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
449 enum v4l2_buf_type type)
450{
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300451 struct vb2_queue *vq;
Pawel Osciak7f986392010-04-23 05:38:37 -0300452 int ret;
453
454 vq = v4l2_m2m_get_vq(m2m_ctx, type);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300455 ret = vb2_streamon(vq, type);
Pawel Osciak7f986392010-04-23 05:38:37 -0300456 if (!ret)
457 v4l2_m2m_try_schedule(m2m_ctx);
458
459 return ret;
460}
461EXPORT_SYMBOL_GPL(v4l2_m2m_streamon);
462
Pawel Osciak7f986392010-04-23 05:38:37 -0300463int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
464 enum v4l2_buf_type type)
465{
John Sheu401f6a22013-02-06 20:03:01 -0300466 struct v4l2_m2m_dev *m2m_dev;
467 struct v4l2_m2m_queue_ctx *q_ctx;
468 unsigned long flags_job, flags;
469 int ret;
Pawel Osciak7f986392010-04-23 05:38:37 -0300470
Shaik Ameer Bashafea564a2013-08-13 02:58:07 -0300471 /* wait until the current context is dequeued from job_queue */
472 v4l2_m2m_cancel_job(m2m_ctx);
473
John Sheu401f6a22013-02-06 20:03:01 -0300474 q_ctx = get_queue_ctx(m2m_ctx, type);
475 ret = vb2_streamoff(&q_ctx->q, type);
476 if (ret)
477 return ret;
478
479 m2m_dev = m2m_ctx->m2m_dev;
480 spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job);
481 /* We should not be scheduled anymore, since we're dropping a queue. */
Philipp Zabeld7bb0ce82013-09-19 04:40:32 -0300482 if (m2m_ctx->job_flags & TRANS_QUEUED)
483 list_del(&m2m_ctx->queue);
John Sheu401f6a22013-02-06 20:03:01 -0300484 m2m_ctx->job_flags = 0;
485
486 spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
487 /* Drop queue, since streamoff returns device to the same state as after
488 * calling reqbufs. */
489 INIT_LIST_HEAD(&q_ctx->rdy_queue);
Philipp Zabel84e68092013-09-19 04:53:21 -0300490 q_ctx->num_rdy = 0;
John Sheu401f6a22013-02-06 20:03:01 -0300491 spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
492
493 if (m2m_dev->curr_ctx == m2m_ctx) {
494 m2m_dev->curr_ctx = NULL;
495 wake_up(&m2m_ctx->finished);
496 }
497 spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
498
499 return 0;
Pawel Osciak7f986392010-04-23 05:38:37 -0300500}
501EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff);
502
Pawel Osciak7f986392010-04-23 05:38:37 -0300503unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
504 struct poll_table_struct *wait)
505{
Hans Verkuil08eb8512012-07-18 10:53:04 -0300506 struct video_device *vfd = video_devdata(file);
507 unsigned long req_events = poll_requested_events(wait);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300508 struct vb2_queue *src_q, *dst_q;
509 struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
Pawel Osciak7f986392010-04-23 05:38:37 -0300510 unsigned int rc = 0;
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300511 unsigned long flags;
Pawel Osciak7f986392010-04-23 05:38:37 -0300512
Hans Verkuil08eb8512012-07-18 10:53:04 -0300513 if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
514 struct v4l2_fh *fh = file->private_data;
515
516 if (v4l2_event_pending(fh))
517 rc = POLLPRI;
518 else if (req_events & POLLPRI)
519 poll_wait(file, &fh->wait, wait);
520 if (!(req_events & (POLLOUT | POLLWRNORM | POLLIN | POLLRDNORM)))
521 return rc;
522 }
523
Pawel Osciak7f986392010-04-23 05:38:37 -0300524 src_q = v4l2_m2m_get_src_vq(m2m_ctx);
525 dst_q = v4l2_m2m_get_dst_vq(m2m_ctx);
526
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300527 /*
528 * There has to be at least one buffer queued on each queued_list, which
529 * means either in driver already or waiting for driver to claim it
530 * and start processing.
531 */
532 if ((!src_q->streaming || list_empty(&src_q->queued_list))
533 && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
Hans Verkuil08eb8512012-07-18 10:53:04 -0300534 rc |= POLLERR;
Pawel Osciak7f986392010-04-23 05:38:37 -0300535 goto end;
536 }
537
Zahari Doychevf1a81af2015-08-17 07:13:53 -0300538 spin_lock_irqsave(&src_q->done_lock, flags);
Seung-Woo Kim57183462013-05-20 23:47:30 -0300539 if (list_empty(&src_q->done_list))
540 poll_wait(file, &src_q->done_wq, wait);
Zahari Doychevf1a81af2015-08-17 07:13:53 -0300541 spin_unlock_irqrestore(&src_q->done_lock, flags);
542
543 spin_lock_irqsave(&dst_q->done_lock, flags);
Philipp Zabelc1621842015-05-04 07:51:06 -0300544 if (list_empty(&dst_q->done_list)) {
545 /*
546 * If the last buffer was dequeued from the capture queue,
547 * return immediately. DQBUF will return -EPIPE.
548 */
Zahari Doychevf1a81af2015-08-17 07:13:53 -0300549 if (dst_q->last_buffer_dequeued) {
550 spin_unlock_irqrestore(&dst_q->done_lock, flags);
Philipp Zabelc1621842015-05-04 07:51:06 -0300551 return rc | POLLIN | POLLRDNORM;
Zahari Doychevf1a81af2015-08-17 07:13:53 -0300552 }
Philipp Zabelc1621842015-05-04 07:51:06 -0300553
Seung-Woo Kim57183462013-05-20 23:47:30 -0300554 poll_wait(file, &dst_q->done_wq, wait);
Philipp Zabelc1621842015-05-04 07:51:06 -0300555 }
Zahari Doychevf1a81af2015-08-17 07:13:53 -0300556 spin_unlock_irqrestore(&dst_q->done_lock, flags);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300557
558 spin_lock_irqsave(&src_q->done_lock, flags);
559 if (!list_empty(&src_q->done_list))
560 src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer,
561 done_entry);
562 if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE
563 || src_vb->state == VB2_BUF_STATE_ERROR))
564 rc |= POLLOUT | POLLWRNORM;
565 spin_unlock_irqrestore(&src_q->done_lock, flags);
566
567 spin_lock_irqsave(&dst_q->done_lock, flags);
568 if (!list_empty(&dst_q->done_list))
569 dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer,
570 done_entry);
571 if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE
572 || dst_vb->state == VB2_BUF_STATE_ERROR))
573 rc |= POLLIN | POLLRDNORM;
574 spin_unlock_irqrestore(&dst_q->done_lock, flags);
Pawel Osciak7f986392010-04-23 05:38:37 -0300575
576end:
Pawel Osciak7f986392010-04-23 05:38:37 -0300577 return rc;
578}
579EXPORT_SYMBOL_GPL(v4l2_m2m_poll);
580
Pawel Osciak7f986392010-04-23 05:38:37 -0300581int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
582 struct vm_area_struct *vma)
583{
584 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300585 struct vb2_queue *vq;
Pawel Osciak7f986392010-04-23 05:38:37 -0300586
587 if (offset < DST_QUEUE_OFF_BASE) {
588 vq = v4l2_m2m_get_src_vq(m2m_ctx);
589 } else {
590 vq = v4l2_m2m_get_dst_vq(m2m_ctx);
591 vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
592 }
593
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300594 return vb2_mmap(vq, vma);
Pawel Osciak7f986392010-04-23 05:38:37 -0300595}
596EXPORT_SYMBOL(v4l2_m2m_mmap);
597
Guennadi Liakhovetskib1252eb2012-09-11 06:32:17 -0300598struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
Pawel Osciak7f986392010-04-23 05:38:37 -0300599{
600 struct v4l2_m2m_dev *m2m_dev;
601
Nicolas THERY3fac4eb2012-10-23 04:47:19 -0300602 if (!m2m_ops || WARN_ON(!m2m_ops->device_run) ||
603 WARN_ON(!m2m_ops->job_abort))
Pawel Osciak7f986392010-04-23 05:38:37 -0300604 return ERR_PTR(-EINVAL);
605
Pawel Osciak7f986392010-04-23 05:38:37 -0300606 m2m_dev = kzalloc(sizeof *m2m_dev, GFP_KERNEL);
607 if (!m2m_dev)
608 return ERR_PTR(-ENOMEM);
609
610 m2m_dev->curr_ctx = NULL;
611 m2m_dev->m2m_ops = m2m_ops;
612 INIT_LIST_HEAD(&m2m_dev->job_queue);
613 spin_lock_init(&m2m_dev->job_spinlock);
614
615 return m2m_dev;
616}
617EXPORT_SYMBOL_GPL(v4l2_m2m_init);
618
Pawel Osciak7f986392010-04-23 05:38:37 -0300619void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
620{
621 kfree(m2m_dev);
622}
623EXPORT_SYMBOL_GPL(v4l2_m2m_release);
624
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300625struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
626 void *drv_priv,
627 int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
Pawel Osciak7f986392010-04-23 05:38:37 -0300628{
629 struct v4l2_m2m_ctx *m2m_ctx;
630 struct v4l2_m2m_queue_ctx *out_q_ctx, *cap_q_ctx;
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300631 int ret;
Pawel Osciak7f986392010-04-23 05:38:37 -0300632
633 m2m_ctx = kzalloc(sizeof *m2m_ctx, GFP_KERNEL);
634 if (!m2m_ctx)
635 return ERR_PTR(-ENOMEM);
636
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300637 m2m_ctx->priv = drv_priv;
Pawel Osciak7f986392010-04-23 05:38:37 -0300638 m2m_ctx->m2m_dev = m2m_dev;
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300639 init_waitqueue_head(&m2m_ctx->finished);
Pawel Osciak7f986392010-04-23 05:38:37 -0300640
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300641 out_q_ctx = &m2m_ctx->out_q_ctx;
642 cap_q_ctx = &m2m_ctx->cap_q_ctx;
Pawel Osciak7f986392010-04-23 05:38:37 -0300643
644 INIT_LIST_HEAD(&out_q_ctx->rdy_queue);
645 INIT_LIST_HEAD(&cap_q_ctx->rdy_queue);
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300646 spin_lock_init(&out_q_ctx->rdy_spinlock);
647 spin_lock_init(&cap_q_ctx->rdy_spinlock);
Pawel Osciak7f986392010-04-23 05:38:37 -0300648
649 INIT_LIST_HEAD(&m2m_ctx->queue);
650
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300651 ret = queue_init(drv_priv, &out_q_ctx->q, &cap_q_ctx->q);
652
653 if (ret)
654 goto err;
Sylwester Nawrocki8e6e8f92013-09-14 18:39:04 -0300655 /*
656 * If both queues use same mutex assign it as the common buffer
657 * queues lock to the m2m context. This lock is used in the
658 * v4l2_m2m_ioctl_* helpers.
659 */
660 if (out_q_ctx->q.lock == cap_q_ctx->q.lock)
661 m2m_ctx->q_lock = out_q_ctx->q.lock;
Pawel Osciak7f986392010-04-23 05:38:37 -0300662
663 return m2m_ctx;
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300664err:
665 kfree(m2m_ctx);
666 return ERR_PTR(ret);
Pawel Osciak7f986392010-04-23 05:38:37 -0300667}
668EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init);
669
Pawel Osciak7f986392010-04-23 05:38:37 -0300670void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx)
671{
Shaik Ameer Bashafea564a2013-08-13 02:58:07 -0300672 /* wait until the current context is dequeued from job_queue */
673 v4l2_m2m_cancel_job(m2m_ctx);
Pawel Osciak7f986392010-04-23 05:38:37 -0300674
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300675 vb2_queue_release(&m2m_ctx->cap_q_ctx.q);
676 vb2_queue_release(&m2m_ctx->out_q_ctx.q);
Pawel Osciak7f986392010-04-23 05:38:37 -0300677
678 kfree(m2m_ctx);
679}
680EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_release);
681
Junghak Sung2d700712015-09-22 10:30:30 -0300682void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx,
683 struct vb2_v4l2_buffer *vbuf)
Pawel Osciak7f986392010-04-23 05:38:37 -0300684{
Junghak Sung2d700712015-09-22 10:30:30 -0300685 struct v4l2_m2m_buffer *b = container_of(vbuf,
686 struct v4l2_m2m_buffer, vb);
Pawel Osciak7f986392010-04-23 05:38:37 -0300687 struct v4l2_m2m_queue_ctx *q_ctx;
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300688 unsigned long flags;
Pawel Osciak7f986392010-04-23 05:38:37 -0300689
Junghak Sung2d700712015-09-22 10:30:30 -0300690 q_ctx = get_queue_ctx(m2m_ctx, vbuf->vb2_buf.vb2_queue->type);
Pawel Osciak7f986392010-04-23 05:38:37 -0300691 if (!q_ctx)
692 return;
693
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300694 spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
695 list_add_tail(&b->list, &q_ctx->rdy_queue);
Pawel Osciak7f986392010-04-23 05:38:37 -0300696 q_ctx->num_rdy++;
Marek Szyprowski908a0d72011-01-12 06:50:24 -0300697 spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
Pawel Osciak7f986392010-04-23 05:38:37 -0300698}
699EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue);
700
Sylwester Nawrocki8e6e8f92013-09-14 18:39:04 -0300701/* Videobuf2 ioctl helpers */
702
703int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv,
704 struct v4l2_requestbuffers *rb)
705{
706 struct v4l2_fh *fh = file->private_data;
707
708 return v4l2_m2m_reqbufs(file, fh->m2m_ctx, rb);
709}
710EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_reqbufs);
711
712int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv,
713 struct v4l2_create_buffers *create)
714{
715 struct v4l2_fh *fh = file->private_data;
716
717 return v4l2_m2m_create_bufs(file, fh->m2m_ctx, create);
718}
719EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs);
720
721int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv,
722 struct v4l2_buffer *buf)
723{
724 struct v4l2_fh *fh = file->private_data;
725
726 return v4l2_m2m_querybuf(file, fh->m2m_ctx, buf);
727}
728EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_querybuf);
729
730int v4l2_m2m_ioctl_qbuf(struct file *file, void *priv,
731 struct v4l2_buffer *buf)
732{
733 struct v4l2_fh *fh = file->private_data;
734
735 return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
736}
737EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_qbuf);
738
739int v4l2_m2m_ioctl_dqbuf(struct file *file, void *priv,
740 struct v4l2_buffer *buf)
741{
742 struct v4l2_fh *fh = file->private_data;
743
744 return v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf);
745}
746EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_dqbuf);
747
Hans Verkuile68cf472015-06-05 11:28:50 -0300748int v4l2_m2m_ioctl_prepare_buf(struct file *file, void *priv,
749 struct v4l2_buffer *buf)
750{
751 struct v4l2_fh *fh = file->private_data;
752
753 return v4l2_m2m_prepare_buf(file, fh->m2m_ctx, buf);
754}
755EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_prepare_buf);
756
Sylwester Nawrocki8e6e8f92013-09-14 18:39:04 -0300757int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv,
758 struct v4l2_exportbuffer *eb)
759{
760 struct v4l2_fh *fh = file->private_data;
761
762 return v4l2_m2m_expbuf(file, fh->m2m_ctx, eb);
763}
764EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_expbuf);
765
766int v4l2_m2m_ioctl_streamon(struct file *file, void *priv,
767 enum v4l2_buf_type type)
768{
769 struct v4l2_fh *fh = file->private_data;
770
771 return v4l2_m2m_streamon(file, fh->m2m_ctx, type);
772}
773EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamon);
774
775int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv,
776 enum v4l2_buf_type type)
777{
778 struct v4l2_fh *fh = file->private_data;
779
780 return v4l2_m2m_streamoff(file, fh->m2m_ctx, type);
781}
782EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff);
783
784/*
785 * v4l2_file_operations helpers. It is assumed here same lock is used
786 * for the output and the capture buffer queue.
787 */
788
789int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma)
790{
791 struct v4l2_fh *fh = file->private_data;
Sylwester Nawrocki8e6e8f92013-09-14 18:39:04 -0300792
Hans Verkuile7525772015-07-20 04:58:24 -0300793 return v4l2_m2m_mmap(file, fh->m2m_ctx, vma);
Sylwester Nawrocki8e6e8f92013-09-14 18:39:04 -0300794}
795EXPORT_SYMBOL_GPL(v4l2_m2m_fop_mmap);
796
797unsigned int v4l2_m2m_fop_poll(struct file *file, poll_table *wait)
798{
799 struct v4l2_fh *fh = file->private_data;
800 struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx;
801 unsigned int ret;
802
803 if (m2m_ctx->q_lock)
804 mutex_lock(m2m_ctx->q_lock);
805
806 ret = v4l2_m2m_poll(file, m2m_ctx, wait);
807
808 if (m2m_ctx->q_lock)
809 mutex_unlock(m2m_ctx->q_lock);
810
811 return ret;
812}
813EXPORT_SYMBOL_GPL(v4l2_m2m_fop_poll);
814