/*
* generic helper functions for handling video4linux capture buffers
*
* (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
*
* Highly based on video-buf written originally by:
* (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
* (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
* (c) 2006 Ted Walther and John Sokol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <media/videobuf-core.h>
#define MAGIC_BUFFER 0x20070728
#define MAGIC_CHECK(is, should) do { \
if (unlikely((is) != (should))) { \
printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \
BUG(); } } while (0)
static int debug;
module_param(debug, int, 0644);
MODULE_DESCRIPTION("helper module to manage video4linux buffers");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
#define dprintk(level, fmt, arg...) do { \
if (debug >= level) \
printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0)
/* --------------------------------------------------------------------- */
#define CALL(q, f, arg...) \
((q->int_ops->f) ? q->int_ops->f(arg) : 0)
void *videobuf_alloc(struct videobuf_queue *q)
{
struct videobuf_buffer *vb;
BUG_ON(q->msize < sizeof(*vb));
if (!q->int_ops || !q->int_ops->alloc) {
printk(KERN_ERR "No specific ops defined!\n");
BUG();
}
vb = q->int_ops->alloc(q->msize);
if (NULL != vb) {
init_waitqueue_head(&vb->done);
vb->magic = MAGIC_BUFFER;
}
return vb;
}
#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
vb->state != VIDEOBUF_QUEUED)
int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
{
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
if (non_blocking) {
if (WAITON_CONDITION)
return 0;
else
return -EAGAIN;
}
if (intr)
return wait_event_interruptible(vb->done, WAITON_CONDITION);
else
wait_event(vb->done, WAITON_CONDITION);
return 0;
}
int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf)
{
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
return CALL(q, iolock, q, vb, fbuf);
}
void *videobuf_queue_to_vmalloc (struct videobuf_queue *q,
struct videobuf_buffer *buf)
{
if (q->int_ops->vmalloc)
return q->int_ops->vmalloc(buf);
else
return NULL;
}
EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
/* --------------------------------------------------------------------- */
void videobuf_queue_core_init(struct videobuf_queue *q,
struct videobuf_queue_ops *ops,
struct device *dev,
spinlock_t *irqlock,
enum v4l2_buf_type type,
enum v4l2_field field,
unsigned int msize,
void *priv,
struct videobuf_qtype_ops *int_ops)
{
memset(q, 0, sizeof(*q));
q->irqlock = irqlock;
q->dev = dev;
q->type = type;
q->field = field;
q->msize = msize;
q->ops = ops;
q->priv_data = priv;
q->int_ops = int_ops;
/* All buffer operations are mandatory */
BUG_ON(!q->ops->buf_setup);
BUG_ON(!q->ops->buf_prepare);
BUG_ON(!q->ops->buf_queue);
BUG_ON(!q->ops->