/*
* 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/sched.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)
struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
{
struct videobuf_buffer *vb;
BUG_ON(q->msize < sizeof(*vb));
if (!q->int_ops || !q->int_ops->alloc_vb) {
printk(KERN_ERR "No specific ops defined!\n");
BUG();
}
vb = q->int_ops->alloc_vb(q->msize);
if (NULL != vb) {
init_waitqueue_head(&vb->done);
vb->magic = MAGIC_BUFFER;
}
return vb;
}
EXPORT_SYMBOL_GPL(videobuf_alloc_vb);
static int is_state_active_or_queued(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
unsigned long flags;
bool rc;
spin_lock_irqsave(q->irqlock, flags);
rc = vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED;
spin_unlock_irqrestore(q->irqlock, flags);
return rc;
};
int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb,
int non_blocking, int intr)
{
bool is_ext_locked;
int ret = 0;
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
if (non_blocking) {
if (is_state_active_or_queued(q, vb))
return 0;
return -EAGAIN;
}
is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock);
/* Release vdev lock to prevent this wait from blocking outside access to
the device. */
if (is_ext_locked)
mutex_unlock(q->ext_lock);
if (intr)
ret = wait_event_interruptible(vb->done, is_state_active_or_queued(q, vb));
else
wait_event(vb->done, is_state_active_or_queued(q, vb));
/* Relock */
if (is_ext_locked)
mutex_lock(q->ext_lock);
return ret;
}
EXPORT_SYMBOL_GPL(videobuf_waiton);