mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
[media] media: videobuf2: Move vb2_fileio_data and vb2_thread to core part
Move things related with vb2 file I/O and vb2_thread without doing any functional changes. After that, videobuf2-internal.h is removed because it is not necessary any more. Signed-off-by: Junghak Sung <jh1009.sung@samsung.com> Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com> Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com> Acked-by: Inki Dae <inki.dae@samsung.com> Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Hans Verkuil <hansverk@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
parent
70433a152f
commit
af3bac1a7c
5 changed files with 817 additions and 818 deletions
|
@ -28,11 +28,155 @@
|
||||||
|
|
||||||
#include <trace/events/vb2.h>
|
#include <trace/events/vb2.h>
|
||||||
|
|
||||||
#include "videobuf2-internal.h"
|
static int debug;
|
||||||
|
module_param(debug, int, 0644);
|
||||||
|
|
||||||
int vb2_debug;
|
#define dprintk(level, fmt, arg...) \
|
||||||
EXPORT_SYMBOL_GPL(vb2_debug);
|
do { \
|
||||||
module_param_named(debug, vb2_debug, int, 0644);
|
if (debug >= level) \
|
||||||
|
pr_info("vb2-core: %s: " fmt, __func__, ## arg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If advanced debugging is on, then count how often each op is called
|
||||||
|
* successfully, which can either be per-buffer or per-queue.
|
||||||
|
*
|
||||||
|
* This makes it easy to check that the 'init' and 'cleanup'
|
||||||
|
* (and variations thereof) stay balanced.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define log_memop(vb, op) \
|
||||||
|
dprintk(2, "call_memop(%p, %d, %s)%s\n", \
|
||||||
|
(vb)->vb2_queue, (vb)->index, #op, \
|
||||||
|
(vb)->vb2_queue->mem_ops->op ? "" : " (nop)")
|
||||||
|
|
||||||
|
#define call_memop(vb, op, args...) \
|
||||||
|
({ \
|
||||||
|
struct vb2_queue *_q = (vb)->vb2_queue; \
|
||||||
|
int err; \
|
||||||
|
\
|
||||||
|
log_memop(vb, op); \
|
||||||
|
err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
|
||||||
|
if (!err) \
|
||||||
|
(vb)->cnt_mem_ ## op++; \
|
||||||
|
err; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define call_ptr_memop(vb, op, args...) \
|
||||||
|
({ \
|
||||||
|
struct vb2_queue *_q = (vb)->vb2_queue; \
|
||||||
|
void *ptr; \
|
||||||
|
\
|
||||||
|
log_memop(vb, op); \
|
||||||
|
ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \
|
||||||
|
if (!IS_ERR_OR_NULL(ptr)) \
|
||||||
|
(vb)->cnt_mem_ ## op++; \
|
||||||
|
ptr; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define call_void_memop(vb, op, args...) \
|
||||||
|
({ \
|
||||||
|
struct vb2_queue *_q = (vb)->vb2_queue; \
|
||||||
|
\
|
||||||
|
log_memop(vb, op); \
|
||||||
|
if (_q->mem_ops->op) \
|
||||||
|
_q->mem_ops->op(args); \
|
||||||
|
(vb)->cnt_mem_ ## op++; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define log_qop(q, op) \
|
||||||
|
dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \
|
||||||
|
(q)->ops->op ? "" : " (nop)")
|
||||||
|
|
||||||
|
#define call_qop(q, op, args...) \
|
||||||
|
({ \
|
||||||
|
int err; \
|
||||||
|
\
|
||||||
|
log_qop(q, op); \
|
||||||
|
err = (q)->ops->op ? (q)->ops->op(args) : 0; \
|
||||||
|
if (!err) \
|
||||||
|
(q)->cnt_ ## op++; \
|
||||||
|
err; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define call_void_qop(q, op, args...) \
|
||||||
|
({ \
|
||||||
|
log_qop(q, op); \
|
||||||
|
if ((q)->ops->op) \
|
||||||
|
(q)->ops->op(args); \
|
||||||
|
(q)->cnt_ ## op++; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define log_vb_qop(vb, op, args...) \
|
||||||
|
dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \
|
||||||
|
(vb)->vb2_queue, (vb)->index, #op, \
|
||||||
|
(vb)->vb2_queue->ops->op ? "" : " (nop)")
|
||||||
|
|
||||||
|
#define call_vb_qop(vb, op, args...) \
|
||||||
|
({ \
|
||||||
|
int err; \
|
||||||
|
\
|
||||||
|
log_vb_qop(vb, op); \
|
||||||
|
err = (vb)->vb2_queue->ops->op ? \
|
||||||
|
(vb)->vb2_queue->ops->op(args) : 0; \
|
||||||
|
if (!err) \
|
||||||
|
(vb)->cnt_ ## op++; \
|
||||||
|
err; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define call_void_vb_qop(vb, op, args...) \
|
||||||
|
({ \
|
||||||
|
log_vb_qop(vb, op); \
|
||||||
|
if ((vb)->vb2_queue->ops->op) \
|
||||||
|
(vb)->vb2_queue->ops->op(args); \
|
||||||
|
(vb)->cnt_ ## op++; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define call_memop(vb, op, args...) \
|
||||||
|
((vb)->vb2_queue->mem_ops->op ? \
|
||||||
|
(vb)->vb2_queue->mem_ops->op(args) : 0)
|
||||||
|
|
||||||
|
#define call_ptr_memop(vb, op, args...) \
|
||||||
|
((vb)->vb2_queue->mem_ops->op ? \
|
||||||
|
(vb)->vb2_queue->mem_ops->op(args) : NULL)
|
||||||
|
|
||||||
|
#define call_void_memop(vb, op, args...) \
|
||||||
|
do { \
|
||||||
|
if ((vb)->vb2_queue->mem_ops->op) \
|
||||||
|
(vb)->vb2_queue->mem_ops->op(args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define call_qop(q, op, args...) \
|
||||||
|
((q)->ops->op ? (q)->ops->op(args) : 0)
|
||||||
|
|
||||||
|
#define call_void_qop(q, op, args...) \
|
||||||
|
do { \
|
||||||
|
if ((q)->ops->op) \
|
||||||
|
(q)->ops->op(args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define call_vb_qop(vb, op, args...) \
|
||||||
|
((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
|
||||||
|
|
||||||
|
#define call_void_vb_qop(vb, op, args...) \
|
||||||
|
do { \
|
||||||
|
if ((vb)->vb2_queue->ops->op) \
|
||||||
|
(vb)->vb2_queue->ops->op(args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define call_bufop(q, op, args...) \
|
||||||
|
({ \
|
||||||
|
int ret = 0; \
|
||||||
|
if (q && q->buf_ops && q->buf_ops->op) \
|
||||||
|
ret = q->buf_ops->op(args); \
|
||||||
|
ret; \
|
||||||
|
})
|
||||||
|
|
||||||
static void __vb2_queue_cancel(struct vb2_queue *q);
|
static void __vb2_queue_cancel(struct vb2_queue *q);
|
||||||
static void __enqueue_in_driver(struct vb2_buffer *vb);
|
static void __enqueue_in_driver(struct vb2_buffer *vb);
|
||||||
|
@ -330,7 +474,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
|
||||||
bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
|
bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
|
||||||
q->cnt_wait_prepare != q->cnt_wait_finish;
|
q->cnt_wait_prepare != q->cnt_wait_finish;
|
||||||
|
|
||||||
if (unbalanced || vb2_debug) {
|
if (unbalanced || debug) {
|
||||||
pr_info("vb2: counters for queue %p:%s\n", q,
|
pr_info("vb2: counters for queue %p:%s\n", q,
|
||||||
unbalanced ? " UNBALANCED!" : "");
|
unbalanced ? " UNBALANCED!" : "");
|
||||||
pr_info("vb2: setup: %u start_streaming: %u stop_streaming: %u\n",
|
pr_info("vb2: setup: %u start_streaming: %u stop_streaming: %u\n",
|
||||||
|
@ -356,7 +500,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
|
||||||
vb->cnt_buf_prepare != vb->cnt_buf_finish ||
|
vb->cnt_buf_prepare != vb->cnt_buf_finish ||
|
||||||
vb->cnt_buf_init != vb->cnt_buf_cleanup;
|
vb->cnt_buf_init != vb->cnt_buf_cleanup;
|
||||||
|
|
||||||
if (unbalanced || vb2_debug) {
|
if (unbalanced || debug) {
|
||||||
pr_info("vb2: counters for queue %p, buffer %d:%s\n",
|
pr_info("vb2: counters for queue %p, buffer %d:%s\n",
|
||||||
q, buffer, unbalanced ? " UNBALANCED!" : "");
|
q, buffer, unbalanced ? " UNBALANCED!" : "");
|
||||||
pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
|
pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
|
||||||
|
@ -2086,6 +2230,8 @@ int vb2_core_queue_init(struct vb2_queue *q)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(vb2_core_queue_init);
|
EXPORT_SYMBOL_GPL(vb2_core_queue_init);
|
||||||
|
|
||||||
|
static int __vb2_init_fileio(struct vb2_queue *q, int read);
|
||||||
|
static int __vb2_cleanup_fileio(struct vb2_queue *q);
|
||||||
/**
|
/**
|
||||||
* vb2_core_queue_release() - stop streaming, release the queue and free memory
|
* vb2_core_queue_release() - stop streaming, release the queue and free memory
|
||||||
* @q: videobuf2 queue
|
* @q: videobuf2 queue
|
||||||
|
@ -2096,6 +2242,7 @@ EXPORT_SYMBOL_GPL(vb2_core_queue_init);
|
||||||
*/
|
*/
|
||||||
void vb2_core_queue_release(struct vb2_queue *q)
|
void vb2_core_queue_release(struct vb2_queue *q)
|
||||||
{
|
{
|
||||||
|
__vb2_cleanup_fileio(q);
|
||||||
__vb2_queue_cancel(q);
|
__vb2_queue_cancel(q);
|
||||||
mutex_lock(&q->mmap_lock);
|
mutex_lock(&q->mmap_lock);
|
||||||
__vb2_queue_free(q, q->num_buffers);
|
__vb2_queue_free(q, q->num_buffers);
|
||||||
|
@ -2103,6 +2250,617 @@ void vb2_core_queue_release(struct vb2_queue *q)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(vb2_core_queue_release);
|
EXPORT_SYMBOL_GPL(vb2_core_queue_release);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vb2_core_poll() - implements poll userspace operation
|
||||||
|
* @q: videobuf2 queue
|
||||||
|
* @file: file argument passed to the poll file operation handler
|
||||||
|
* @wait: wait argument passed to the poll file operation handler
|
||||||
|
*
|
||||||
|
* This function implements poll file operation handler for a driver.
|
||||||
|
* For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will
|
||||||
|
* be informed that the file descriptor of a video device is available for
|
||||||
|
* reading.
|
||||||
|
* For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
|
||||||
|
* will be reported as available for writing.
|
||||||
|
*
|
||||||
|
* The return values from this function are intended to be directly returned
|
||||||
|
* from poll handler in driver.
|
||||||
|
*/
|
||||||
|
unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file,
|
||||||
|
poll_table *wait)
|
||||||
|
{
|
||||||
|
unsigned long req_events = poll_requested_events(wait);
|
||||||
|
struct vb2_buffer *vb = NULL;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM)))
|
||||||
|
return 0;
|
||||||
|
if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start file I/O emulator only if streaming API has not been used yet.
|
||||||
|
*/
|
||||||
|
if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
|
||||||
|
if (!q->is_output && (q->io_modes & VB2_READ) &&
|
||||||
|
(req_events & (POLLIN | POLLRDNORM))) {
|
||||||
|
if (__vb2_init_fileio(q, 1))
|
||||||
|
return POLLERR;
|
||||||
|
}
|
||||||
|
if (q->is_output && (q->io_modes & VB2_WRITE) &&
|
||||||
|
(req_events & (POLLOUT | POLLWRNORM))) {
|
||||||
|
if (__vb2_init_fileio(q, 0))
|
||||||
|
return POLLERR;
|
||||||
|
/*
|
||||||
|
* Write to OUTPUT queue can be done immediately.
|
||||||
|
*/
|
||||||
|
return POLLOUT | POLLWRNORM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is nothing to wait for if the queue isn't streaming, or if the
|
||||||
|
* error flag is set.
|
||||||
|
*/
|
||||||
|
if (!vb2_is_streaming(q) || q->error)
|
||||||
|
return POLLERR;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For output streams you can call write() as long as there are fewer
|
||||||
|
* buffers queued than there are buffers available.
|
||||||
|
*/
|
||||||
|
if (q->is_output && q->fileio && q->queued_count < q->num_buffers)
|
||||||
|
return POLLOUT | POLLWRNORM;
|
||||||
|
|
||||||
|
if (list_empty(&q->done_list)) {
|
||||||
|
/*
|
||||||
|
* If the last buffer was dequeued from a capture queue,
|
||||||
|
* return immediately. DQBUF will return -EPIPE.
|
||||||
|
*/
|
||||||
|
if (q->last_buffer_dequeued)
|
||||||
|
return POLLIN | POLLRDNORM;
|
||||||
|
|
||||||
|
poll_wait(file, &q->done_wq, wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Take first buffer available for dequeuing.
|
||||||
|
*/
|
||||||
|
spin_lock_irqsave(&q->done_lock, flags);
|
||||||
|
if (!list_empty(&q->done_list))
|
||||||
|
vb = list_first_entry(&q->done_list, struct vb2_buffer,
|
||||||
|
done_entry);
|
||||||
|
spin_unlock_irqrestore(&q->done_lock, flags);
|
||||||
|
|
||||||
|
if (vb && (vb->state == VB2_BUF_STATE_DONE
|
||||||
|
|| vb->state == VB2_BUF_STATE_ERROR)) {
|
||||||
|
return (q->is_output) ?
|
||||||
|
POLLOUT | POLLWRNORM :
|
||||||
|
POLLIN | POLLRDNORM;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(vb2_core_poll);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct vb2_fileio_buf - buffer context used by file io emulator
|
||||||
|
*
|
||||||
|
* vb2 provides a compatibility layer and emulator of file io (read and
|
||||||
|
* write) calls on top of streaming API. This structure is used for
|
||||||
|
* tracking context related to the buffers.
|
||||||
|
*/
|
||||||
|
struct vb2_fileio_buf {
|
||||||
|
void *vaddr;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int pos;
|
||||||
|
unsigned int queued:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct vb2_fileio_data - queue context used by file io emulator
|
||||||
|
*
|
||||||
|
* @cur_index: the index of the buffer currently being read from or
|
||||||
|
* written to. If equal to q->num_buffers then a new buffer
|
||||||
|
* must be dequeued.
|
||||||
|
* @initial_index: in the read() case all buffers are queued up immediately
|
||||||
|
* in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
|
||||||
|
* buffers. However, in the write() case no buffers are initially
|
||||||
|
* queued, instead whenever a buffer is full it is queued up by
|
||||||
|
* __vb2_perform_fileio(). Only once all available buffers have
|
||||||
|
* been queued up will __vb2_perform_fileio() start to dequeue
|
||||||
|
* buffers. This means that initially __vb2_perform_fileio()
|
||||||
|
* needs to know what buffer index to use when it is queuing up
|
||||||
|
* the buffers for the first time. That initial index is stored
|
||||||
|
* in this field. Once it is equal to q->num_buffers all
|
||||||
|
* available buffers have been queued and __vb2_perform_fileio()
|
||||||
|
* should start the normal dequeue/queue cycle.
|
||||||
|
*
|
||||||
|
* vb2 provides a compatibility layer and emulator of file io (read and
|
||||||
|
* write) calls on top of streaming API. For proper operation it required
|
||||||
|
* this structure to save the driver state between each call of the read
|
||||||
|
* or write function.
|
||||||
|
*/
|
||||||
|
struct vb2_fileio_data {
|
||||||
|
unsigned int count;
|
||||||
|
unsigned int type;
|
||||||
|
unsigned int memory;
|
||||||
|
struct vb2_buffer *b;
|
||||||
|
struct vb2_fileio_buf bufs[VB2_MAX_FRAME];
|
||||||
|
unsigned int cur_index;
|
||||||
|
unsigned int initial_index;
|
||||||
|
unsigned int q_count;
|
||||||
|
unsigned int dq_count;
|
||||||
|
unsigned read_once:1;
|
||||||
|
unsigned write_immediately:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __vb2_init_fileio() - initialize file io emulator
|
||||||
|
* @q: videobuf2 queue
|
||||||
|
* @read: mode selector (1 means read, 0 means write)
|
||||||
|
*/
|
||||||
|
static int __vb2_init_fileio(struct vb2_queue *q, int read)
|
||||||
|
{
|
||||||
|
struct vb2_fileio_data *fileio;
|
||||||
|
int i, ret;
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check
|
||||||
|
*/
|
||||||
|
if (WARN_ON((read && !(q->io_modes & VB2_READ)) ||
|
||||||
|
(!read && !(q->io_modes & VB2_WRITE))))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if device supports mapping buffers to kernel virtual space.
|
||||||
|
*/
|
||||||
|
if (!q->mem_ops->vaddr)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if streaming api has not been already activated.
|
||||||
|
*/
|
||||||
|
if (q->streaming || q->num_buffers > 0)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start with count 1, driver can increase it in queue_setup()
|
||||||
|
*/
|
||||||
|
count = 1;
|
||||||
|
|
||||||
|
dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
|
||||||
|
(read) ? "read" : "write", count, q->fileio_read_once,
|
||||||
|
q->fileio_write_immediately);
|
||||||
|
|
||||||
|
fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL);
|
||||||
|
if (fileio == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
fileio->b = kzalloc(q->buf_struct_size, GFP_KERNEL);
|
||||||
|
if (fileio->b == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
fileio->read_once = q->fileio_read_once;
|
||||||
|
fileio->write_immediately = q->fileio_write_immediately;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request buffers and use MMAP type to force driver
|
||||||
|
* to allocate buffers by itself.
|
||||||
|
*/
|
||||||
|
fileio->count = count;
|
||||||
|
fileio->memory = VB2_MEMORY_MMAP;
|
||||||
|
fileio->type = q->type;
|
||||||
|
q->fileio = fileio;
|
||||||
|
ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count);
|
||||||
|
if (ret)
|
||||||
|
goto err_kfree;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if plane_count is correct
|
||||||
|
* (multiplane buffers are not supported).
|
||||||
|
*/
|
||||||
|
if (q->bufs[0]->num_planes != 1) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto err_reqbufs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get kernel address of each buffer.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < q->num_buffers; i++) {
|
||||||
|
fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
|
||||||
|
if (fileio->bufs[i].vaddr == NULL) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err_reqbufs;
|
||||||
|
}
|
||||||
|
fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read mode requires pre queuing of all buffers.
|
||||||
|
*/
|
||||||
|
if (read) {
|
||||||
|
/*
|
||||||
|
* Queue all buffers.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < q->num_buffers; i++) {
|
||||||
|
struct vb2_buffer *b = fileio->b;
|
||||||
|
|
||||||
|
memset(b, 0, q->buf_struct_size);
|
||||||
|
b->type = q->type;
|
||||||
|
b->memory = q->memory;
|
||||||
|
b->index = i;
|
||||||
|
ret = vb2_core_qbuf(q, i, b);
|
||||||
|
if (ret)
|
||||||
|
goto err_reqbufs;
|
||||||
|
fileio->bufs[i].queued = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* All buffers have been queued, so mark that by setting
|
||||||
|
* initial_index to q->num_buffers
|
||||||
|
*/
|
||||||
|
fileio->initial_index = q->num_buffers;
|
||||||
|
fileio->cur_index = q->num_buffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start streaming.
|
||||||
|
*/
|
||||||
|
ret = vb2_core_streamon(q, q->type);
|
||||||
|
if (ret)
|
||||||
|
goto err_reqbufs;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
err_reqbufs:
|
||||||
|
fileio->count = 0;
|
||||||
|
vb2_core_reqbufs(q, fileio->memory, &fileio->count);
|
||||||
|
|
||||||
|
err_kfree:
|
||||||
|
q->fileio = NULL;
|
||||||
|
kfree(fileio);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __vb2_cleanup_fileio() - free resourced used by file io emulator
|
||||||
|
* @q: videobuf2 queue
|
||||||
|
*/
|
||||||
|
static int __vb2_cleanup_fileio(struct vb2_queue *q)
|
||||||
|
{
|
||||||
|
struct vb2_fileio_data *fileio = q->fileio;
|
||||||
|
|
||||||
|
if (fileio) {
|
||||||
|
vb2_core_streamoff(q, q->type);
|
||||||
|
q->fileio = NULL;
|
||||||
|
fileio->count = 0;
|
||||||
|
vb2_core_reqbufs(q, fileio->memory, &fileio->count);
|
||||||
|
kfree(fileio->b);
|
||||||
|
kfree(fileio);
|
||||||
|
dprintk(3, "file io emulator closed\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __vb2_perform_fileio() - perform a single file io (read or write) operation
|
||||||
|
* @q: videobuf2 queue
|
||||||
|
* @data: pointed to target userspace buffer
|
||||||
|
* @count: number of bytes to read or write
|
||||||
|
* @ppos: file handle position tracking pointer
|
||||||
|
* @nonblock: mode selector (1 means blocking calls, 0 means nonblocking)
|
||||||
|
* @read: access mode selector (1 means read, 0 means write)
|
||||||
|
*/
|
||||||
|
static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
|
||||||
|
loff_t *ppos, int nonblock, int read)
|
||||||
|
{
|
||||||
|
struct vb2_fileio_data *fileio;
|
||||||
|
struct vb2_fileio_buf *buf;
|
||||||
|
bool is_multiplanar = q->is_multiplanar;
|
||||||
|
/*
|
||||||
|
* When using write() to write data to an output video node the vb2 core
|
||||||
|
* should copy timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody
|
||||||
|
* else is able to provide this information with the write() operation.
|
||||||
|
*/
|
||||||
|
bool copy_timestamp = !read && q->copy_timestamp;
|
||||||
|
int ret, index;
|
||||||
|
|
||||||
|
dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n",
|
||||||
|
read ? "read" : "write", (long)*ppos, count,
|
||||||
|
nonblock ? "non" : "");
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize emulator on first call.
|
||||||
|
*/
|
||||||
|
if (!vb2_fileio_is_active(q)) {
|
||||||
|
ret = __vb2_init_fileio(q, read);
|
||||||
|
dprintk(3, "vb2_init_fileio result: %d\n", ret);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fileio = q->fileio;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we need to dequeue the buffer.
|
||||||
|
*/
|
||||||
|
index = fileio->cur_index;
|
||||||
|
if (index >= q->num_buffers) {
|
||||||
|
struct vb2_buffer *b = fileio->b;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call vb2_dqbuf to get buffer back.
|
||||||
|
*/
|
||||||
|
memset(b, 0, q->buf_struct_size);
|
||||||
|
b->type = q->type;
|
||||||
|
b->memory = q->memory;
|
||||||
|
ret = vb2_core_dqbuf(q, b, nonblock);
|
||||||
|
dprintk(5, "vb2_dqbuf result: %d\n", ret);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
fileio->dq_count += 1;
|
||||||
|
|
||||||
|
fileio->cur_index = index = b->index;
|
||||||
|
buf = &fileio->bufs[index];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get number of bytes filled by the driver
|
||||||
|
*/
|
||||||
|
buf->pos = 0;
|
||||||
|
buf->queued = 0;
|
||||||
|
buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
|
||||||
|
: vb2_plane_size(q->bufs[index], 0);
|
||||||
|
/* Compensate for data_offset on read in the multiplanar case. */
|
||||||
|
if (is_multiplanar && read &&
|
||||||
|
b->planes[0].data_offset < buf->size) {
|
||||||
|
buf->pos = b->planes[0].data_offset;
|
||||||
|
buf->size -= buf->pos;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf = &fileio->bufs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limit count on last few bytes of the buffer.
|
||||||
|
*/
|
||||||
|
if (buf->pos + count > buf->size) {
|
||||||
|
count = buf->size - buf->pos;
|
||||||
|
dprintk(5, "reducing read count: %zd\n", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transfer data to userspace.
|
||||||
|
*/
|
||||||
|
dprintk(3, "copying %zd bytes - buffer %d, offset %u\n",
|
||||||
|
count, index, buf->pos);
|
||||||
|
if (read)
|
||||||
|
ret = copy_to_user(data, buf->vaddr + buf->pos, count);
|
||||||
|
else
|
||||||
|
ret = copy_from_user(buf->vaddr + buf->pos, data, count);
|
||||||
|
if (ret) {
|
||||||
|
dprintk(3, "error copying data\n");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update counters.
|
||||||
|
*/
|
||||||
|
buf->pos += count;
|
||||||
|
*ppos += count;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Queue next buffer if required.
|
||||||
|
*/
|
||||||
|
if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
|
||||||
|
struct vb2_buffer *b = fileio->b;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if this is the last buffer to read.
|
||||||
|
*/
|
||||||
|
if (read && fileio->read_once && fileio->dq_count == 1) {
|
||||||
|
dprintk(3, "read limit reached\n");
|
||||||
|
return __vb2_cleanup_fileio(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call vb2_qbuf and give buffer to the driver.
|
||||||
|
*/
|
||||||
|
memset(b, 0, q->buf_struct_size);
|
||||||
|
b->type = q->type;
|
||||||
|
b->memory = q->memory;
|
||||||
|
b->index = index;
|
||||||
|
b->planes[0].bytesused = buf->pos;
|
||||||
|
|
||||||
|
if (copy_timestamp)
|
||||||
|
b->timestamp = ktime_get_ns();
|
||||||
|
ret = vb2_core_qbuf(q, index, b);
|
||||||
|
dprintk(5, "vb2_dbuf result: %d\n", ret);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buffer has been queued, update the status
|
||||||
|
*/
|
||||||
|
buf->pos = 0;
|
||||||
|
buf->queued = 1;
|
||||||
|
buf->size = vb2_plane_size(q->bufs[index], 0);
|
||||||
|
fileio->q_count += 1;
|
||||||
|
/*
|
||||||
|
* If we are queuing up buffers for the first time, then
|
||||||
|
* increase initial_index by one.
|
||||||
|
*/
|
||||||
|
if (fileio->initial_index < q->num_buffers)
|
||||||
|
fileio->initial_index++;
|
||||||
|
/*
|
||||||
|
* The next buffer to use is either a buffer that's going to be
|
||||||
|
* queued for the first time (initial_index < q->num_buffers)
|
||||||
|
* or it is equal to q->num_buffers, meaning that the next
|
||||||
|
* time we need to dequeue a buffer since we've now queued up
|
||||||
|
* all the 'first time' buffers.
|
||||||
|
*/
|
||||||
|
fileio->cur_index = fileio->initial_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return proper number of bytes processed.
|
||||||
|
*/
|
||||||
|
if (ret == 0)
|
||||||
|
ret = count;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
|
||||||
|
loff_t *ppos, int nonblocking)
|
||||||
|
{
|
||||||
|
return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(vb2_read);
|
||||||
|
|
||||||
|
size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
|
||||||
|
loff_t *ppos, int nonblocking)
|
||||||
|
{
|
||||||
|
return __vb2_perform_fileio(q, (char __user *) data, count,
|
||||||
|
ppos, nonblocking, 0);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(vb2_write);
|
||||||
|
|
||||||
|
struct vb2_threadio_data {
|
||||||
|
struct task_struct *thread;
|
||||||
|
vb2_thread_fnc fnc;
|
||||||
|
void *priv;
|
||||||
|
bool stop;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int vb2_thread(void *data)
|
||||||
|
{
|
||||||
|
struct vb2_queue *q = data;
|
||||||
|
struct vb2_threadio_data *threadio = q->threadio;
|
||||||
|
struct vb2_fileio_data *fileio = q->fileio;
|
||||||
|
bool copy_timestamp = false;
|
||||||
|
int prequeue = 0;
|
||||||
|
int index = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (q->is_output) {
|
||||||
|
prequeue = q->num_buffers;
|
||||||
|
copy_timestamp = q->copy_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_freezable();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct vb2_buffer *vb;
|
||||||
|
struct vb2_buffer *b = fileio->b;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call vb2_dqbuf to get buffer back.
|
||||||
|
*/
|
||||||
|
memset(b, 0, q->buf_struct_size);
|
||||||
|
b->type = q->type;
|
||||||
|
b->memory = q->memory;
|
||||||
|
if (prequeue) {
|
||||||
|
b->index = index++;
|
||||||
|
prequeue--;
|
||||||
|
} else {
|
||||||
|
call_void_qop(q, wait_finish, q);
|
||||||
|
if (!threadio->stop)
|
||||||
|
ret = vb2_core_dqbuf(q, b, 0);
|
||||||
|
call_void_qop(q, wait_prepare, q);
|
||||||
|
dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
|
||||||
|
}
|
||||||
|
if (ret || threadio->stop)
|
||||||
|
break;
|
||||||
|
try_to_freeze();
|
||||||
|
|
||||||
|
vb = q->bufs[b->index];
|
||||||
|
if (b->state == VB2_BUF_STATE_DONE)
|
||||||
|
if (threadio->fnc(vb, threadio->priv))
|
||||||
|
break;
|
||||||
|
call_void_qop(q, wait_finish, q);
|
||||||
|
if (copy_timestamp)
|
||||||
|
b->timestamp = ktime_get_ns();;
|
||||||
|
if (!threadio->stop)
|
||||||
|
ret = vb2_core_qbuf(q, b->index, b);
|
||||||
|
call_void_qop(q, wait_prepare, q);
|
||||||
|
if (ret || threadio->stop)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hmm, linux becomes *very* unhappy without this ... */
|
||||||
|
while (!kthread_should_stop()) {
|
||||||
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
|
schedule();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function should not be used for anything else but the videobuf2-dvb
|
||||||
|
* support. If you think you have another good use-case for this, then please
|
||||||
|
* contact the linux-media mailinglist first.
|
||||||
|
*/
|
||||||
|
int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
|
||||||
|
const char *thread_name)
|
||||||
|
{
|
||||||
|
struct vb2_threadio_data *threadio;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (q->threadio)
|
||||||
|
return -EBUSY;
|
||||||
|
if (vb2_is_busy(q))
|
||||||
|
return -EBUSY;
|
||||||
|
if (WARN_ON(q->fileio))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
threadio = kzalloc(sizeof(*threadio), GFP_KERNEL);
|
||||||
|
if (threadio == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
threadio->fnc = fnc;
|
||||||
|
threadio->priv = priv;
|
||||||
|
|
||||||
|
ret = __vb2_init_fileio(q, !q->is_output);
|
||||||
|
dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
|
||||||
|
if (ret)
|
||||||
|
goto nomem;
|
||||||
|
q->threadio = threadio;
|
||||||
|
threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);
|
||||||
|
if (IS_ERR(threadio->thread)) {
|
||||||
|
ret = PTR_ERR(threadio->thread);
|
||||||
|
threadio->thread = NULL;
|
||||||
|
goto nothread;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nothread:
|
||||||
|
__vb2_cleanup_fileio(q);
|
||||||
|
nomem:
|
||||||
|
kfree(threadio);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(vb2_thread_start);
|
||||||
|
|
||||||
|
int vb2_thread_stop(struct vb2_queue *q)
|
||||||
|
{
|
||||||
|
struct vb2_threadio_data *threadio = q->threadio;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (threadio == NULL)
|
||||||
|
return 0;
|
||||||
|
threadio->stop = true;
|
||||||
|
/* Wake up all pending sleeps in the thread */
|
||||||
|
vb2_queue_error(q);
|
||||||
|
err = kthread_stop(threadio->thread);
|
||||||
|
__vb2_cleanup_fileio(q);
|
||||||
|
threadio->thread = NULL;
|
||||||
|
kfree(threadio);
|
||||||
|
q->threadio = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(vb2_thread_stop);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
|
MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
|
||||||
MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
|
MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -1,161 +0,0 @@
|
||||||
#ifndef _MEDIA_VIDEOBUF2_INTERNAL_H
|
|
||||||
#define _MEDIA_VIDEOBUF2_INTERNAL_H
|
|
||||||
|
|
||||||
#include <linux/err.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <media/videobuf2-core.h>
|
|
||||||
|
|
||||||
extern int vb2_debug;
|
|
||||||
|
|
||||||
#define dprintk(level, fmt, arg...) \
|
|
||||||
do { \
|
|
||||||
if (vb2_debug >= level) \
|
|
||||||
pr_info("vb2: %s: " fmt, __func__, ## arg); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If advanced debugging is on, then count how often each op is called
|
|
||||||
* successfully, which can either be per-buffer or per-queue.
|
|
||||||
*
|
|
||||||
* This makes it easy to check that the 'init' and 'cleanup'
|
|
||||||
* (and variations thereof) stay balanced.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define log_memop(vb, op) \
|
|
||||||
dprintk(2, "call_memop(%p, %d, %s)%s\n", \
|
|
||||||
(vb)->vb2_queue, (vb)->index, #op, \
|
|
||||||
(vb)->vb2_queue->mem_ops->op ? "" : " (nop)")
|
|
||||||
|
|
||||||
#define call_memop(vb, op, args...) \
|
|
||||||
({ \
|
|
||||||
struct vb2_queue *_q = (vb)->vb2_queue; \
|
|
||||||
int err; \
|
|
||||||
\
|
|
||||||
log_memop(vb, op); \
|
|
||||||
err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
|
|
||||||
if (!err) \
|
|
||||||
(vb)->cnt_mem_ ## op++; \
|
|
||||||
err; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define call_ptr_memop(vb, op, args...) \
|
|
||||||
({ \
|
|
||||||
struct vb2_queue *_q = (vb)->vb2_queue; \
|
|
||||||
void *ptr; \
|
|
||||||
\
|
|
||||||
log_memop(vb, op); \
|
|
||||||
ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \
|
|
||||||
if (!IS_ERR_OR_NULL(ptr)) \
|
|
||||||
(vb)->cnt_mem_ ## op++; \
|
|
||||||
ptr; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define call_void_memop(vb, op, args...) \
|
|
||||||
({ \
|
|
||||||
struct vb2_queue *_q = (vb)->vb2_queue; \
|
|
||||||
\
|
|
||||||
log_memop(vb, op); \
|
|
||||||
if (_q->mem_ops->op) \
|
|
||||||
_q->mem_ops->op(args); \
|
|
||||||
(vb)->cnt_mem_ ## op++; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define log_qop(q, op) \
|
|
||||||
dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \
|
|
||||||
(q)->ops->op ? "" : " (nop)")
|
|
||||||
|
|
||||||
#define call_qop(q, op, args...) \
|
|
||||||
({ \
|
|
||||||
int err; \
|
|
||||||
\
|
|
||||||
log_qop(q, op); \
|
|
||||||
err = (q)->ops->op ? (q)->ops->op(args) : 0; \
|
|
||||||
if (!err) \
|
|
||||||
(q)->cnt_ ## op++; \
|
|
||||||
err; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define call_void_qop(q, op, args...) \
|
|
||||||
({ \
|
|
||||||
log_qop(q, op); \
|
|
||||||
if ((q)->ops->op) \
|
|
||||||
(q)->ops->op(args); \
|
|
||||||
(q)->cnt_ ## op++; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define log_vb_qop(vb, op, args...) \
|
|
||||||
dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \
|
|
||||||
(vb)->vb2_queue, (vb)->index, #op, \
|
|
||||||
(vb)->vb2_queue->ops->op ? "" : " (nop)")
|
|
||||||
|
|
||||||
#define call_vb_qop(vb, op, args...) \
|
|
||||||
({ \
|
|
||||||
int err; \
|
|
||||||
\
|
|
||||||
log_vb_qop(vb, op); \
|
|
||||||
err = (vb)->vb2_queue->ops->op ? \
|
|
||||||
(vb)->vb2_queue->ops->op(args) : 0; \
|
|
||||||
if (!err) \
|
|
||||||
(vb)->cnt_ ## op++; \
|
|
||||||
err; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define call_void_vb_qop(vb, op, args...) \
|
|
||||||
({ \
|
|
||||||
log_vb_qop(vb, op); \
|
|
||||||
if ((vb)->vb2_queue->ops->op) \
|
|
||||||
(vb)->vb2_queue->ops->op(args); \
|
|
||||||
(vb)->cnt_ ## op++; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define call_memop(vb, op, args...) \
|
|
||||||
((vb)->vb2_queue->mem_ops->op ? \
|
|
||||||
(vb)->vb2_queue->mem_ops->op(args) : 0)
|
|
||||||
|
|
||||||
#define call_ptr_memop(vb, op, args...) \
|
|
||||||
((vb)->vb2_queue->mem_ops->op ? \
|
|
||||||
(vb)->vb2_queue->mem_ops->op(args) : NULL)
|
|
||||||
|
|
||||||
#define call_void_memop(vb, op, args...) \
|
|
||||||
do { \
|
|
||||||
if ((vb)->vb2_queue->mem_ops->op) \
|
|
||||||
(vb)->vb2_queue->mem_ops->op(args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define call_qop(q, op, args...) \
|
|
||||||
((q)->ops->op ? (q)->ops->op(args) : 0)
|
|
||||||
|
|
||||||
#define call_void_qop(q, op, args...) \
|
|
||||||
do { \
|
|
||||||
if ((q)->ops->op) \
|
|
||||||
(q)->ops->op(args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define call_vb_qop(vb, op, args...) \
|
|
||||||
((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
|
|
||||||
|
|
||||||
#define call_void_vb_qop(vb, op, args...) \
|
|
||||||
do { \
|
|
||||||
if ((vb)->vb2_queue->ops->op) \
|
|
||||||
(vb)->vb2_queue->ops->op(args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define call_bufop(q, op, args...) \
|
|
||||||
({ \
|
|
||||||
int ret = 0; \
|
|
||||||
if (q && q->buf_ops && q->buf_ops->op) \
|
|
||||||
ret = q->buf_ops->op(args); \
|
|
||||||
ret; \
|
|
||||||
})
|
|
||||||
|
|
||||||
bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb);
|
|
||||||
int vb2_verify_memory_type(struct vb2_queue *q,
|
|
||||||
enum vb2_memory memory, unsigned int type);
|
|
||||||
#endif /* _MEDIA_VIDEOBUF2_INTERNAL_H */
|
|
|
@ -31,7 +31,14 @@
|
||||||
|
|
||||||
#include <media/videobuf2-v4l2.h>
|
#include <media/videobuf2-v4l2.h>
|
||||||
|
|
||||||
#include "videobuf2-internal.h"
|
static int debug;
|
||||||
|
module_param(debug, int, 0644);
|
||||||
|
|
||||||
|
#define dprintk(level, fmt, arg...) \
|
||||||
|
do { \
|
||||||
|
if (debug >= level) \
|
||||||
|
pr_info("vb2-v4l2: %s: " fmt, __func__, ## arg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* Flags that are set by the vb2 core */
|
/* Flags that are set by the vb2 core */
|
||||||
#define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
|
#define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
|
||||||
|
@ -765,9 +772,6 @@ int vb2_queue_init(struct vb2_queue *q)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(vb2_queue_init);
|
EXPORT_SYMBOL_GPL(vb2_queue_init);
|
||||||
|
|
||||||
static int __vb2_init_fileio(struct vb2_queue *q, int read);
|
|
||||||
static int __vb2_cleanup_fileio(struct vb2_queue *q);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vb2_queue_release() - stop streaming, release the queue and free memory
|
* vb2_queue_release() - stop streaming, release the queue and free memory
|
||||||
* @q: videobuf2 queue
|
* @q: videobuf2 queue
|
||||||
|
@ -778,102 +782,10 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q);
|
||||||
*/
|
*/
|
||||||
void vb2_queue_release(struct vb2_queue *q)
|
void vb2_queue_release(struct vb2_queue *q)
|
||||||
{
|
{
|
||||||
__vb2_cleanup_fileio(q);
|
|
||||||
vb2_core_queue_release(q);
|
vb2_core_queue_release(q);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(vb2_queue_release);
|
EXPORT_SYMBOL_GPL(vb2_queue_release);
|
||||||
|
|
||||||
/**
|
|
||||||
* vb2_core_poll() - implements poll userspace operation
|
|
||||||
* @q: videobuf2 queue
|
|
||||||
* @file: file argument passed to the poll file operation handler
|
|
||||||
* @wait: wait argument passed to the poll file operation handler
|
|
||||||
*
|
|
||||||
* This function implements poll file operation handler for a driver.
|
|
||||||
* For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will
|
|
||||||
* be informed that the file descriptor of a video device is available for
|
|
||||||
* reading.
|
|
||||||
* For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
|
|
||||||
* will be reported as available for writing.
|
|
||||||
*
|
|
||||||
* The return values from this function are intended to be directly returned
|
|
||||||
* from poll handler in driver.
|
|
||||||
*/
|
|
||||||
unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file,
|
|
||||||
poll_table *wait)
|
|
||||||
{
|
|
||||||
unsigned long req_events = poll_requested_events(wait);
|
|
||||||
struct vb2_buffer *vb = NULL;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM)))
|
|
||||||
return 0;
|
|
||||||
if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start file I/O emulator only if streaming API has not been used yet.
|
|
||||||
*/
|
|
||||||
if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
|
|
||||||
if (!q->is_output && (q->io_modes & VB2_READ) &&
|
|
||||||
(req_events & (POLLIN | POLLRDNORM))) {
|
|
||||||
if (__vb2_init_fileio(q, 1))
|
|
||||||
return POLLERR;
|
|
||||||
}
|
|
||||||
if (q->is_output && (q->io_modes & VB2_WRITE) &&
|
|
||||||
(req_events & (POLLOUT | POLLWRNORM))) {
|
|
||||||
if (__vb2_init_fileio(q, 0))
|
|
||||||
return POLLERR;
|
|
||||||
/*
|
|
||||||
* Write to OUTPUT queue can be done immediately.
|
|
||||||
*/
|
|
||||||
return POLLOUT | POLLWRNORM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There is nothing to wait for if the queue isn't streaming, or if the
|
|
||||||
* error flag is set.
|
|
||||||
*/
|
|
||||||
if (!vb2_is_streaming(q) || q->error)
|
|
||||||
return POLLERR;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For output streams you can call write() as long as there are fewer
|
|
||||||
* buffers queued than there are buffers available.
|
|
||||||
*/
|
|
||||||
if (q->is_output && q->fileio && q->queued_count < q->num_buffers)
|
|
||||||
return POLLOUT | POLLWRNORM;
|
|
||||||
|
|
||||||
if (list_empty(&q->done_list)) {
|
|
||||||
/*
|
|
||||||
* If the last buffer was dequeued from a capture queue,
|
|
||||||
* return immediately. DQBUF will return -EPIPE.
|
|
||||||
*/
|
|
||||||
if (q->last_buffer_dequeued)
|
|
||||||
return POLLIN | POLLRDNORM;
|
|
||||||
|
|
||||||
poll_wait(file, &q->done_wq, wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Take first buffer available for dequeuing.
|
|
||||||
*/
|
|
||||||
spin_lock_irqsave(&q->done_lock, flags);
|
|
||||||
if (!list_empty(&q->done_list))
|
|
||||||
vb = list_first_entry(&q->done_list, struct vb2_buffer,
|
|
||||||
done_entry);
|
|
||||||
spin_unlock_irqrestore(&q->done_lock, flags);
|
|
||||||
|
|
||||||
if (vb && (vb->state == VB2_BUF_STATE_DONE
|
|
||||||
|| vb->state == VB2_BUF_STATE_ERROR)) {
|
|
||||||
return (q->is_output) ?
|
|
||||||
POLLOUT | POLLWRNORM :
|
|
||||||
POLLIN | POLLRDNORM;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vb2_poll() - implements poll userspace operation
|
* vb2_poll() - implements poll userspace operation
|
||||||
* @q: videobuf2 queue
|
* @q: videobuf2 queue
|
||||||
|
@ -920,525 +832,6 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(vb2_poll);
|
EXPORT_SYMBOL_GPL(vb2_poll);
|
||||||
|
|
||||||
/**
|
|
||||||
* struct vb2_fileio_buf - buffer context used by file io emulator
|
|
||||||
*
|
|
||||||
* vb2 provides a compatibility layer and emulator of file io (read and
|
|
||||||
* write) calls on top of streaming API. This structure is used for
|
|
||||||
* tracking context related to the buffers.
|
|
||||||
*/
|
|
||||||
struct vb2_fileio_buf {
|
|
||||||
void *vaddr;
|
|
||||||
unsigned int size;
|
|
||||||
unsigned int pos;
|
|
||||||
unsigned int queued:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct vb2_fileio_data - queue context used by file io emulator
|
|
||||||
*
|
|
||||||
* @cur_index: the index of the buffer currently being read from or
|
|
||||||
* written to. If equal to q->num_buffers then a new buffer
|
|
||||||
* must be dequeued.
|
|
||||||
* @initial_index: in the read() case all buffers are queued up immediately
|
|
||||||
* in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
|
|
||||||
* buffers. However, in the write() case no buffers are initially
|
|
||||||
* queued, instead whenever a buffer is full it is queued up by
|
|
||||||
* __vb2_perform_fileio(). Only once all available buffers have
|
|
||||||
* been queued up will __vb2_perform_fileio() start to dequeue
|
|
||||||
* buffers. This means that initially __vb2_perform_fileio()
|
|
||||||
* needs to know what buffer index to use when it is queuing up
|
|
||||||
* the buffers for the first time. That initial index is stored
|
|
||||||
* in this field. Once it is equal to q->num_buffers all
|
|
||||||
* available buffers have been queued and __vb2_perform_fileio()
|
|
||||||
* should start the normal dequeue/queue cycle.
|
|
||||||
*
|
|
||||||
* vb2 provides a compatibility layer and emulator of file io (read and
|
|
||||||
* write) calls on top of streaming API. For proper operation it required
|
|
||||||
* this structure to save the driver state between each call of the read
|
|
||||||
* or write function.
|
|
||||||
*/
|
|
||||||
struct vb2_fileio_data {
|
|
||||||
unsigned int count;
|
|
||||||
unsigned int type;
|
|
||||||
unsigned int memory;
|
|
||||||
struct vb2_buffer *b;
|
|
||||||
struct vb2_fileio_buf bufs[VB2_MAX_FRAME];
|
|
||||||
unsigned int cur_index;
|
|
||||||
unsigned int initial_index;
|
|
||||||
unsigned int q_count;
|
|
||||||
unsigned int dq_count;
|
|
||||||
unsigned read_once:1;
|
|
||||||
unsigned write_immediately:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __vb2_init_fileio() - initialize file io emulator
|
|
||||||
* @q: videobuf2 queue
|
|
||||||
* @read: mode selector (1 means read, 0 means write)
|
|
||||||
*/
|
|
||||||
static int __vb2_init_fileio(struct vb2_queue *q, int read)
|
|
||||||
{
|
|
||||||
struct vb2_fileio_data *fileio;
|
|
||||||
int i, ret;
|
|
||||||
unsigned int count = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sanity check
|
|
||||||
*/
|
|
||||||
if (WARN_ON((read && !(q->io_modes & VB2_READ)) ||
|
|
||||||
(!read && !(q->io_modes & VB2_WRITE))))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if device supports mapping buffers to kernel virtual space.
|
|
||||||
*/
|
|
||||||
if (!q->mem_ops->vaddr)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if streaming api has not been already activated.
|
|
||||||
*/
|
|
||||||
if (q->streaming || q->num_buffers > 0)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start with count 1, driver can increase it in queue_setup()
|
|
||||||
*/
|
|
||||||
count = 1;
|
|
||||||
|
|
||||||
dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
|
|
||||||
(read) ? "read" : "write", count, q->fileio_read_once,
|
|
||||||
q->fileio_write_immediately);
|
|
||||||
|
|
||||||
fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL);
|
|
||||||
if (fileio == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
fileio->b = kzalloc(q->buf_struct_size, GFP_KERNEL);
|
|
||||||
if (fileio->b == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
fileio->read_once = q->fileio_read_once;
|
|
||||||
fileio->write_immediately = q->fileio_write_immediately;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Request buffers and use MMAP type to force driver
|
|
||||||
* to allocate buffers by itself.
|
|
||||||
*/
|
|
||||||
fileio->count = count;
|
|
||||||
fileio->memory = VB2_MEMORY_MMAP;
|
|
||||||
fileio->type = q->type;
|
|
||||||
q->fileio = fileio;
|
|
||||||
ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count);
|
|
||||||
if (ret)
|
|
||||||
goto err_kfree;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if plane_count is correct
|
|
||||||
* (multiplane buffers are not supported).
|
|
||||||
*/
|
|
||||||
if (q->bufs[0]->num_planes != 1) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto err_reqbufs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get kernel address of each buffer.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < q->num_buffers; i++) {
|
|
||||||
fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
|
|
||||||
if (fileio->bufs[i].vaddr == NULL) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto err_reqbufs;
|
|
||||||
}
|
|
||||||
fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read mode requires pre queuing of all buffers.
|
|
||||||
*/
|
|
||||||
if (read) {
|
|
||||||
/*
|
|
||||||
* Queue all buffers.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < q->num_buffers; i++) {
|
|
||||||
struct vb2_buffer *b = fileio->b;
|
|
||||||
|
|
||||||
memset(b, 0, q->buf_struct_size);
|
|
||||||
b->type = q->type;
|
|
||||||
b->memory = q->memory;
|
|
||||||
b->index = i;
|
|
||||||
ret = vb2_core_qbuf(q, i, b);
|
|
||||||
if (ret)
|
|
||||||
goto err_reqbufs;
|
|
||||||
fileio->bufs[i].queued = 1;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* All buffers have been queued, so mark that by setting
|
|
||||||
* initial_index to q->num_buffers
|
|
||||||
*/
|
|
||||||
fileio->initial_index = q->num_buffers;
|
|
||||||
fileio->cur_index = q->num_buffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start streaming.
|
|
||||||
*/
|
|
||||||
ret = vb2_core_streamon(q, q->type);
|
|
||||||
if (ret)
|
|
||||||
goto err_reqbufs;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
err_reqbufs:
|
|
||||||
fileio->count = 0;
|
|
||||||
vb2_core_reqbufs(q, fileio->memory, &fileio->count);
|
|
||||||
|
|
||||||
err_kfree:
|
|
||||||
q->fileio = NULL;
|
|
||||||
kfree(fileio);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __vb2_cleanup_fileio() - free resourced used by file io emulator
|
|
||||||
* @q: videobuf2 queue
|
|
||||||
*/
|
|
||||||
static int __vb2_cleanup_fileio(struct vb2_queue *q)
|
|
||||||
{
|
|
||||||
struct vb2_fileio_data *fileio = q->fileio;
|
|
||||||
|
|
||||||
if (fileio) {
|
|
||||||
vb2_core_streamoff(q, q->type);
|
|
||||||
q->fileio = NULL;
|
|
||||||
fileio->count = 0;
|
|
||||||
vb2_core_reqbufs(q, fileio->memory, &fileio->count);
|
|
||||||
kfree(fileio->b);
|
|
||||||
kfree(fileio);
|
|
||||||
dprintk(3, "file io emulator closed\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __vb2_perform_fileio() - perform a single file io (read or write) operation
|
|
||||||
* @q: videobuf2 queue
|
|
||||||
* @data: pointed to target userspace buffer
|
|
||||||
* @count: number of bytes to read or write
|
|
||||||
* @ppos: file handle position tracking pointer
|
|
||||||
* @nonblock: mode selector (1 means blocking calls, 0 means nonblocking)
|
|
||||||
* @read: access mode selector (1 means read, 0 means write)
|
|
||||||
*/
|
|
||||||
static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
|
|
||||||
loff_t *ppos, int nonblock, int read)
|
|
||||||
{
|
|
||||||
struct vb2_fileio_data *fileio;
|
|
||||||
struct vb2_fileio_buf *buf;
|
|
||||||
bool is_multiplanar = q->is_multiplanar;
|
|
||||||
/*
|
|
||||||
* When using write() to write data to an output video node the vb2 core
|
|
||||||
* should copy timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody
|
|
||||||
* else is able to provide this information with the write() operation.
|
|
||||||
*/
|
|
||||||
bool copy_timestamp = !read && q->copy_timestamp;
|
|
||||||
int ret, index;
|
|
||||||
|
|
||||||
dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n",
|
|
||||||
read ? "read" : "write", (long)*ppos, count,
|
|
||||||
nonblock ? "non" : "");
|
|
||||||
|
|
||||||
if (!data)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize emulator on first call.
|
|
||||||
*/
|
|
||||||
if (!vb2_fileio_is_active(q)) {
|
|
||||||
ret = __vb2_init_fileio(q, read);
|
|
||||||
dprintk(3, "vb2_init_fileio result: %d\n", ret);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
fileio = q->fileio;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if we need to dequeue the buffer.
|
|
||||||
*/
|
|
||||||
index = fileio->cur_index;
|
|
||||||
if (index >= q->num_buffers) {
|
|
||||||
struct vb2_buffer *b = fileio->b;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call vb2_dqbuf to get buffer back.
|
|
||||||
*/
|
|
||||||
memset(b, 0, q->buf_struct_size);
|
|
||||||
b->type = q->type;
|
|
||||||
b->memory = q->memory;
|
|
||||||
ret = vb2_core_dqbuf(q, b, nonblock);
|
|
||||||
dprintk(5, "vb2_dqbuf result: %d\n", ret);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
fileio->dq_count += 1;
|
|
||||||
|
|
||||||
fileio->cur_index = index = b->index;
|
|
||||||
buf = &fileio->bufs[index];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get number of bytes filled by the driver
|
|
||||||
*/
|
|
||||||
buf->pos = 0;
|
|
||||||
buf->queued = 0;
|
|
||||||
buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
|
|
||||||
: vb2_plane_size(q->bufs[index], 0);
|
|
||||||
/* Compensate for data_offset on read in the multiplanar case. */
|
|
||||||
if (is_multiplanar && read &&
|
|
||||||
b->planes[0].data_offset < buf->size) {
|
|
||||||
buf->pos = b->planes[0].data_offset;
|
|
||||||
buf->size -= buf->pos;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buf = &fileio->bufs[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Limit count on last few bytes of the buffer.
|
|
||||||
*/
|
|
||||||
if (buf->pos + count > buf->size) {
|
|
||||||
count = buf->size - buf->pos;
|
|
||||||
dprintk(5, "reducing read count: %zd\n", count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Transfer data to userspace.
|
|
||||||
*/
|
|
||||||
dprintk(3, "copying %zd bytes - buffer %d, offset %u\n",
|
|
||||||
count, index, buf->pos);
|
|
||||||
if (read)
|
|
||||||
ret = copy_to_user(data, buf->vaddr + buf->pos, count);
|
|
||||||
else
|
|
||||||
ret = copy_from_user(buf->vaddr + buf->pos, data, count);
|
|
||||||
if (ret) {
|
|
||||||
dprintk(3, "error copying data\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update counters.
|
|
||||||
*/
|
|
||||||
buf->pos += count;
|
|
||||||
*ppos += count;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Queue next buffer if required.
|
|
||||||
*/
|
|
||||||
if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
|
|
||||||
struct vb2_buffer *b = fileio->b;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if this is the last buffer to read.
|
|
||||||
*/
|
|
||||||
if (read && fileio->read_once && fileio->dq_count == 1) {
|
|
||||||
dprintk(3, "read limit reached\n");
|
|
||||||
return __vb2_cleanup_fileio(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call vb2_qbuf and give buffer to the driver.
|
|
||||||
*/
|
|
||||||
memset(b, 0, q->buf_struct_size);
|
|
||||||
b->type = q->type;
|
|
||||||
b->memory = q->memory;
|
|
||||||
b->index = index;
|
|
||||||
b->planes[0].bytesused = buf->pos;
|
|
||||||
|
|
||||||
if (copy_timestamp)
|
|
||||||
b->timestamp = ktime_get_ns();
|
|
||||||
ret = vb2_core_qbuf(q, index, b);
|
|
||||||
dprintk(5, "vb2_dbuf result: %d\n", ret);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Buffer has been queued, update the status
|
|
||||||
*/
|
|
||||||
buf->pos = 0;
|
|
||||||
buf->queued = 1;
|
|
||||||
buf->size = vb2_plane_size(q->bufs[index], 0);
|
|
||||||
fileio->q_count += 1;
|
|
||||||
/*
|
|
||||||
* If we are queuing up buffers for the first time, then
|
|
||||||
* increase initial_index by one.
|
|
||||||
*/
|
|
||||||
if (fileio->initial_index < q->num_buffers)
|
|
||||||
fileio->initial_index++;
|
|
||||||
/*
|
|
||||||
* The next buffer to use is either a buffer that's going to be
|
|
||||||
* queued for the first time (initial_index < q->num_buffers)
|
|
||||||
* or it is equal to q->num_buffers, meaning that the next
|
|
||||||
* time we need to dequeue a buffer since we've now queued up
|
|
||||||
* all the 'first time' buffers.
|
|
||||||
*/
|
|
||||||
fileio->cur_index = fileio->initial_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return proper number of bytes processed.
|
|
||||||
*/
|
|
||||||
if (ret == 0)
|
|
||||||
ret = count;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
|
|
||||||
loff_t *ppos, int nonblocking)
|
|
||||||
{
|
|
||||||
return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(vb2_read);
|
|
||||||
|
|
||||||
size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
|
|
||||||
loff_t *ppos, int nonblocking)
|
|
||||||
{
|
|
||||||
return __vb2_perform_fileio(q, (char __user *) data, count,
|
|
||||||
ppos, nonblocking, 0);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(vb2_write);
|
|
||||||
|
|
||||||
struct vb2_threadio_data {
|
|
||||||
struct task_struct *thread;
|
|
||||||
vb2_thread_fnc fnc;
|
|
||||||
void *priv;
|
|
||||||
bool stop;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int vb2_thread(void *data)
|
|
||||||
{
|
|
||||||
struct vb2_queue *q = data;
|
|
||||||
struct vb2_threadio_data *threadio = q->threadio;
|
|
||||||
struct vb2_fileio_data *fileio = q->fileio;
|
|
||||||
bool copy_timestamp = false;
|
|
||||||
int prequeue = 0;
|
|
||||||
int index = 0;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (q->is_output) {
|
|
||||||
prequeue = q->num_buffers;
|
|
||||||
copy_timestamp = q->copy_timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_freezable();
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
struct vb2_buffer *vb;
|
|
||||||
struct vb2_buffer *b = fileio->b;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call vb2_dqbuf to get buffer back.
|
|
||||||
*/
|
|
||||||
memset(b, 0, q->buf_struct_size);
|
|
||||||
b->type = q->type;
|
|
||||||
b->memory = q->memory;
|
|
||||||
if (prequeue) {
|
|
||||||
b->index = index++;
|
|
||||||
prequeue--;
|
|
||||||
} else {
|
|
||||||
call_void_qop(q, wait_finish, q);
|
|
||||||
if (!threadio->stop)
|
|
||||||
ret = vb2_core_dqbuf(q, b, 0);
|
|
||||||
call_void_qop(q, wait_prepare, q);
|
|
||||||
dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
|
|
||||||
}
|
|
||||||
if (ret || threadio->stop)
|
|
||||||
break;
|
|
||||||
try_to_freeze();
|
|
||||||
|
|
||||||
vb = q->bufs[b->index];
|
|
||||||
if (b->state == VB2_BUF_STATE_DONE)
|
|
||||||
if (threadio->fnc(vb, threadio->priv))
|
|
||||||
break;
|
|
||||||
call_void_qop(q, wait_finish, q);
|
|
||||||
if (copy_timestamp)
|
|
||||||
b->timestamp = ktime_get_ns();
|
|
||||||
if (!threadio->stop)
|
|
||||||
ret = vb2_core_qbuf(q, b->index, b);
|
|
||||||
call_void_qop(q, wait_prepare, q);
|
|
||||||
if (ret || threadio->stop)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hmm, linux becomes *very* unhappy without this ... */
|
|
||||||
while (!kthread_should_stop()) {
|
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
|
||||||
schedule();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function should not be used for anything else but the videobuf2-dvb
|
|
||||||
* support. If you think you have another good use-case for this, then please
|
|
||||||
* contact the linux-media mailinglist first.
|
|
||||||
*/
|
|
||||||
int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
|
|
||||||
const char *thread_name)
|
|
||||||
{
|
|
||||||
struct vb2_threadio_data *threadio;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (q->threadio)
|
|
||||||
return -EBUSY;
|
|
||||||
if (vb2_is_busy(q))
|
|
||||||
return -EBUSY;
|
|
||||||
if (WARN_ON(q->fileio))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
threadio = kzalloc(sizeof(*threadio), GFP_KERNEL);
|
|
||||||
if (threadio == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
threadio->fnc = fnc;
|
|
||||||
threadio->priv = priv;
|
|
||||||
|
|
||||||
ret = __vb2_init_fileio(q, !q->is_output);
|
|
||||||
dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
|
|
||||||
if (ret)
|
|
||||||
goto nomem;
|
|
||||||
q->threadio = threadio;
|
|
||||||
threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);
|
|
||||||
if (IS_ERR(threadio->thread)) {
|
|
||||||
ret = PTR_ERR(threadio->thread);
|
|
||||||
threadio->thread = NULL;
|
|
||||||
goto nothread;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
nothread:
|
|
||||||
__vb2_cleanup_fileio(q);
|
|
||||||
nomem:
|
|
||||||
kfree(threadio);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(vb2_thread_start);
|
|
||||||
|
|
||||||
int vb2_thread_stop(struct vb2_queue *q)
|
|
||||||
{
|
|
||||||
struct vb2_threadio_data *threadio = q->threadio;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (threadio == NULL)
|
|
||||||
return 0;
|
|
||||||
threadio->stop = true;
|
|
||||||
/* Wake up all pending sleeps in the thread */
|
|
||||||
vb2_queue_error(q);
|
|
||||||
err = kthread_stop(threadio->thread);
|
|
||||||
__vb2_cleanup_fileio(q);
|
|
||||||
threadio->thread = NULL;
|
|
||||||
kfree(threadio);
|
|
||||||
q->threadio = NULL;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(vb2_thread_stop);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following functions are not part of the vb2 core API, but are helper
|
* The following functions are not part of the vb2 core API, but are helper
|
||||||
* functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations
|
* functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations
|
||||||
|
|
|
@ -541,6 +541,42 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
|
||||||
unsigned long pgoff,
|
unsigned long pgoff,
|
||||||
unsigned long flags);
|
unsigned long flags);
|
||||||
#endif
|
#endif
|
||||||
|
unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file,
|
||||||
|
poll_table *wait);
|
||||||
|
size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
|
||||||
|
loff_t *ppos, int nonblock);
|
||||||
|
size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
|
||||||
|
loff_t *ppos, int nonblock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vb2_thread_fnc - callback function for use with vb2_thread
|
||||||
|
*
|
||||||
|
* This is called whenever a buffer is dequeued in the thread.
|
||||||
|
*/
|
||||||
|
typedef int (*vb2_thread_fnc)(struct vb2_buffer *vb, void *priv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vb2_thread_start() - start a thread for the given queue.
|
||||||
|
* @q: videobuf queue
|
||||||
|
* @fnc: callback function
|
||||||
|
* @priv: priv pointer passed to the callback function
|
||||||
|
* @thread_name:the name of the thread. This will be prefixed with "vb2-".
|
||||||
|
*
|
||||||
|
* This starts a thread that will queue and dequeue until an error occurs
|
||||||
|
* or @vb2_thread_stop is called.
|
||||||
|
*
|
||||||
|
* This function should not be used for anything else but the videobuf2-dvb
|
||||||
|
* support. If you think you have another good use-case for this, then please
|
||||||
|
* contact the linux-media mailinglist first.
|
||||||
|
*/
|
||||||
|
int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
|
||||||
|
const char *thread_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vb2_thread_stop() - stop the thread for the given queue.
|
||||||
|
* @q: videobuf queue
|
||||||
|
*/
|
||||||
|
int vb2_thread_stop(struct vb2_queue *q);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vb2_is_streaming() - return streaming status of the queue
|
* vb2_is_streaming() - return streaming status of the queue
|
||||||
|
@ -645,4 +681,11 @@ static inline void vb2_clear_last_buffer_dequeued(struct vb2_queue *q)
|
||||||
q->last_buffer_dequeued = false;
|
q->last_buffer_dequeued = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following functions are not part of the vb2 core API, but are useful
|
||||||
|
* functions for videobuf2-*.
|
||||||
|
*/
|
||||||
|
bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb);
|
||||||
|
int vb2_verify_memory_type(struct vb2_queue *q,
|
||||||
|
enum vb2_memory memory, unsigned int type);
|
||||||
#endif /* _MEDIA_VIDEOBUF2_CORE_H */
|
#endif /* _MEDIA_VIDEOBUF2_CORE_H */
|
||||||
|
|
|
@ -63,42 +63,8 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
|
||||||
|
|
||||||
int __must_check vb2_queue_init(struct vb2_queue *q);
|
int __must_check vb2_queue_init(struct vb2_queue *q);
|
||||||
void vb2_queue_release(struct vb2_queue *q);
|
void vb2_queue_release(struct vb2_queue *q);
|
||||||
|
unsigned int vb2_poll(struct vb2_queue *q, struct file *file,
|
||||||
unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
|
poll_table *wait);
|
||||||
size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
|
|
||||||
loff_t *ppos, int nonblock);
|
|
||||||
size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
|
|
||||||
loff_t *ppos, int nonblock);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* vb2_thread_fnc - callback function for use with vb2_thread
|
|
||||||
*
|
|
||||||
* This is called whenever a buffer is dequeued in the thread.
|
|
||||||
*/
|
|
||||||
typedef int (*vb2_thread_fnc)(struct vb2_buffer *vb, void *priv);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* vb2_thread_start() - start a thread for the given queue.
|
|
||||||
* @q: videobuf queue
|
|
||||||
* @fnc: callback function
|
|
||||||
* @priv: priv pointer passed to the callback function
|
|
||||||
* @thread_name:the name of the thread. This will be prefixed with "vb2-".
|
|
||||||
*
|
|
||||||
* This starts a thread that will queue and dequeue until an error occurs
|
|
||||||
* or @vb2_thread_stop is called.
|
|
||||||
*
|
|
||||||
* This function should not be used for anything else but the videobuf2-dvb
|
|
||||||
* support. If you think you have another good use-case for this, then please
|
|
||||||
* contact the linux-media mailinglist first.
|
|
||||||
*/
|
|
||||||
int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
|
|
||||||
const char *thread_name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* vb2_thread_stop() - stop the thread for the given queue.
|
|
||||||
* @q: videobuf queue
|
|
||||||
*/
|
|
||||||
int vb2_thread_stop(struct vb2_queue *q);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following functions are not part of the vb2 core API, but are simple
|
* The following functions are not part of the vb2 core API, but are simple
|
||||||
|
|
Loading…
Reference in a new issue