2007-08-23 23:26:14 +04:00
/*
* 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>
2008-07-24 08:28:13 +04:00
# include <linux/mm.h>
2009-10-07 17:09:06 +04:00
# include <linux/sched.h>
2007-08-23 23:26:14 +04:00
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <media/videobuf-core.h>
# define MAGIC_BUFFER 0x20070728
2010-03-17 10:01:04 +03:00
# define MAGIC_CHECK(is, should) \
do { \
if ( unlikely ( ( is ) ! = ( should ) ) ) { \
printk ( KERN_ERR \
" magic mismatch: %x (expected %x) \n " , \
is , should ) ; \
BUG ( ) ; \
} \
} while ( 0 )
2007-08-23 23:26:14 +04:00
2007-12-10 16:53:20 +03:00
static int debug ;
2007-08-23 23:26:14 +04:00
module_param ( debug , int , 0644 ) ;
MODULE_DESCRIPTION ( " helper module to manage video4linux buffers " ) ;
MODULE_AUTHOR ( " Mauro Carvalho Chehab <mchehab@infradead.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2010-03-17 10:01:04 +03:00
# define dprintk(level, fmt, arg...) \
do { \
if ( debug > = level ) \
printk ( KERN_DEBUG " vbuf: " fmt , # # arg ) ; \
} while ( 0 )
2007-08-23 23:26:14 +04:00
/* --------------------------------------------------------------------- */
# define CALL(q, f, arg...) \
2007-12-10 16:53:20 +03:00
( ( q - > int_ops - > f ) ? q - > int_ops - > f ( arg ) : 0 )
2007-08-23 23:26:14 +04:00
2010-05-11 17:36:28 +04:00
struct videobuf_buffer * videobuf_alloc_vb ( struct videobuf_queue * q )
2007-08-23 23:26:14 +04:00
{
struct videobuf_buffer * vb ;
2007-12-10 16:53:20 +03:00
BUG_ON ( q - > msize < sizeof ( * vb ) ) ;
2007-08-23 23:26:14 +04:00
2010-05-11 17:36:28 +04:00
if ( ! q - > int_ops | | ! q - > int_ops - > alloc_vb ) {
2007-08-23 23:26:14 +04:00
printk ( KERN_ERR " No specific ops defined! \n " ) ;
BUG ( ) ;
}
2010-05-11 17:36:28 +04:00
vb = q - > int_ops - > alloc_vb ( q - > msize ) ;
2007-08-23 23:26:14 +04:00
if ( NULL ! = vb ) {
init_waitqueue_head ( & vb - > done ) ;
2010-03-17 10:01:04 +03:00
vb - > magic = MAGIC_BUFFER ;
2007-08-23 23:26:14 +04:00
}
return vb ;
}
2010-05-11 17:36:28 +04:00
EXPORT_SYMBOL_GPL ( videobuf_alloc_vb ) ;
2007-08-23 23:26:14 +04:00
2010-09-26 16:01:26 +04:00
static int is_state_active_or_queued ( struct videobuf_queue * q , struct videobuf_buffer * vb )
2007-08-23 23:26:14 +04:00
{
2010-09-26 16:01:26 +04:00
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 ;
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( vb - > magic , MAGIC_BUFFER ) ;
2008-04-03 01:10:59 +04:00
if ( non_blocking ) {
2010-09-26 16:01:26 +04:00
if ( is_state_active_or_queued ( q , vb ) )
2008-04-03 01:10:59 +04:00
return 0 ;
2010-09-26 16:01:26 +04:00
return - EAGAIN ;
2007-08-23 23:26:14 +04:00
}
2008-04-03 01:10:59 +04:00
2010-09-26 16:01:26 +04:00
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 ) ;
2008-04-03 01:10:59 +04:00
if ( intr )
2010-09-26 16:01:26 +04:00
ret = wait_event_interruptible ( vb - > done , is_state_active_or_queued ( q , vb ) ) ;
2008-04-03 01:10:59 +04:00
else
2010-09-26 16:01:26 +04:00
wait_event ( vb - > done , is_state_active_or_queued ( q , vb ) ) ;
/* Relock */
if ( is_ext_locked )
mutex_lock ( q - > ext_lock ) ;
2008-04-03 01:10:59 +04:00
2010-09-26 16:01:26 +04:00
return ret ;
2007-08-23 23:26:14 +04:00
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_waiton ) ;
2007-08-23 23:26:14 +04:00
2007-12-10 16:53:20 +03:00
int videobuf_iolock ( struct videobuf_queue * q , struct videobuf_buffer * vb ,
2007-08-23 23:26:14 +04:00
struct v4l2_framebuffer * fbuf )
{
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( vb - > magic , MAGIC_BUFFER ) ;
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-08-23 23:26:14 +04:00
2007-12-10 16:53:20 +03:00
return CALL ( q , iolock , q , vb , fbuf ) ;
2007-08-23 23:26:14 +04:00
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_iolock ) ;
2007-08-23 23:26:14 +04:00
2010-03-28 15:33:23 +04:00
void * videobuf_queue_to_vaddr ( struct videobuf_queue * q ,
struct videobuf_buffer * buf )
2008-04-13 22:10:00 +04:00
{
2010-03-28 15:18:37 +04:00
if ( q - > int_ops - > vaddr )
return q - > int_ops - > vaddr ( buf ) ;
2010-03-28 15:33:23 +04:00
return NULL ;
2008-04-13 22:10:00 +04:00
}
2010-03-28 15:33:23 +04:00
EXPORT_SYMBOL_GPL ( videobuf_queue_to_vaddr ) ;
2008-04-13 22:10:00 +04:00
2007-08-23 23:26:14 +04:00
/* --------------------------------------------------------------------- */
2007-12-10 16:53:20 +03:00
void videobuf_queue_core_init ( struct videobuf_queue * q ,
2009-11-18 01:43:41 +03:00
const struct videobuf_queue_ops * ops ,
2008-04-22 21:46:02 +04:00
struct device * dev ,
2007-08-23 23:26:14 +04:00
spinlock_t * irqlock ,
enum v4l2_buf_type type ,
enum v4l2_field field ,
unsigned int msize ,
2007-10-08 19:20:02 +04:00
void * priv ,
2010-09-21 00:39:46 +04:00
struct videobuf_qtype_ops * int_ops ,
struct mutex * ext_lock )
2007-08-23 23:26:14 +04:00
{
2009-06-03 06:01:04 +04:00
BUG_ON ( ! q ) ;
2007-12-10 16:53:20 +03:00
memset ( q , 0 , sizeof ( * q ) ) ;
2007-10-08 19:20:02 +04:00
q - > irqlock = irqlock ;
2010-09-21 00:39:46 +04:00
q - > ext_lock = ext_lock ;
2007-10-08 19:20:02 +04:00
q - > dev = dev ;
q - > type = type ;
q - > field = field ;
q - > msize = msize ;
q - > ops = ops ;
2007-08-23 23:26:14 +04:00
q - > priv_data = priv ;
2007-10-08 19:20:02 +04:00
q - > int_ops = int_ops ;
2007-08-23 23:26:14 +04:00
/* All buffer operations are mandatory */
2007-12-10 16:53:20 +03:00
BUG_ON ( ! q - > ops - > buf_setup ) ;
BUG_ON ( ! q - > ops - > buf_prepare ) ;
BUG_ON ( ! q - > ops - > buf_queue ) ;
BUG_ON ( ! q - > ops - > buf_release ) ;
2007-08-23 23:26:14 +04:00
2008-03-28 20:18:33 +03:00
/* Lock is mandatory for queue_cancel to work */
BUG_ON ( ! irqlock ) ;
2007-10-08 19:20:02 +04:00
/* Having implementations for abstract methods are mandatory */
2007-12-10 16:53:20 +03:00
BUG_ON ( ! q - > int_ops ) ;
2007-10-08 19:20:02 +04:00
2008-01-31 19:57:53 +03:00
mutex_init ( & q - > vb_lock ) ;
2008-04-03 01:10:59 +04:00
init_waitqueue_head ( & q - > wait ) ;
2007-08-23 23:26:14 +04:00
INIT_LIST_HEAD ( & q - > stream ) ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_queue_core_init ) ;
2007-08-23 23:26:14 +04:00
2007-11-14 02:05:38 +03:00
/* Locking: Only usage in bttv unsafe find way to remove */
2007-08-23 23:26:14 +04:00
int videobuf_queue_is_busy ( struct videobuf_queue * q )
{
int i ;
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-08-23 23:26:14 +04:00
if ( q - > streaming ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " busy: streaming active \n " ) ;
2007-08-23 23:26:14 +04:00
return 1 ;
}
if ( q - > reading ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " busy: pending read #1 \n " ) ;
2007-08-23 23:26:14 +04:00
return 1 ;
}
if ( q - > read_buf ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " busy: pending read #2 \n " ) ;
2007-08-23 23:26:14 +04:00
return 1 ;
}
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + ) {
if ( NULL = = q - > bufs [ i ] )
continue ;
2007-09-28 01:25:44 +04:00
if ( q - > bufs [ i ] - > map ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " busy: buffer #%d mapped \n " , i ) ;
2007-08-23 23:26:14 +04:00
return 1 ;
}
2007-11-07 02:02:36 +03:00
if ( q - > bufs [ i ] - > state = = VIDEOBUF_QUEUED ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " busy: buffer #%d queued \n " , i ) ;
2007-08-23 23:26:14 +04:00
return 1 ;
}
2007-11-07 02:02:36 +03:00
if ( q - > bufs [ i ] - > state = = VIDEOBUF_ACTIVE ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " busy: buffer #%d avtive \n " , i ) ;
2007-08-23 23:26:14 +04:00
return 1 ;
}
}
return 0 ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_queue_is_busy ) ;
2007-08-23 23:26:14 +04:00
2010-05-11 17:36:29 +04:00
/**
* __videobuf_free ( ) - free all the buffers and their control structures
*
* This function can only be called if streaming / reading is off , i . e . no buffers
* are under control of the driver .
*/
/* Locking: Caller holds q->vb_lock */
static int __videobuf_free ( struct videobuf_queue * q )
{
int i ;
dprintk ( 1 , " %s \n " , __func__ ) ;
if ( ! q )
return 0 ;
if ( q - > streaming | | q - > reading ) {
dprintk ( 1 , " Cannot free buffers when streaming or reading \n " ) ;
return - EBUSY ;
}
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + )
if ( q - > bufs [ i ] & & q - > bufs [ i ] - > map ) {
dprintk ( 1 , " Cannot free mmapped buffers \n " ) ;
return - EBUSY ;
}
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + ) {
if ( NULL = = q - > bufs [ i ] )
continue ;
q - > ops - > buf_release ( q , q - > bufs [ i ] ) ;
kfree ( q - > bufs [ i ] ) ;
q - > bufs [ i ] = NULL ;
}
return 0 ;
}
2008-01-31 19:57:53 +03:00
/* Locking: Caller holds q->vb_lock */
2007-08-23 23:26:14 +04:00
void videobuf_queue_cancel ( struct videobuf_queue * q )
{
2007-12-10 16:53:20 +03:00
unsigned long flags = 0 ;
2007-08-23 23:26:14 +04:00
int i ;
2008-04-03 01:10:59 +04:00
q - > streaming = 0 ;
q - > reading = 0 ;
wake_up_interruptible_sync ( & q - > wait ) ;
2007-08-23 23:26:14 +04:00
/* remove queued buffers from list */
2008-03-28 20:18:33 +03:00
spin_lock_irqsave ( q - > irqlock , flags ) ;
2007-08-23 23:26:14 +04:00
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + ) {
if ( NULL = = q - > bufs [ i ] )
continue ;
2007-11-07 02:02:36 +03:00
if ( q - > bufs [ i ] - > state = = VIDEOBUF_QUEUED ) {
2007-08-23 23:26:14 +04:00
list_del ( & q - > bufs [ i ] - > queue ) ;
2007-11-07 02:02:36 +03:00
q - > bufs [ i ] - > state = VIDEOBUF_ERROR ;
2008-04-03 01:10:57 +04:00
wake_up_all ( & q - > bufs [ i ] - > done ) ;
2007-08-23 23:26:14 +04:00
}
}
2008-03-28 20:18:33 +03:00
spin_unlock_irqrestore ( q - > irqlock , flags ) ;
2007-08-23 23:26:14 +04:00
/* free all buffers + clear queue */
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + ) {
if ( NULL = = q - > bufs [ i ] )
continue ;
2007-12-10 16:53:20 +03:00
q - > ops - > buf_release ( q , q - > bufs [ i ] ) ;
2007-08-23 23:26:14 +04:00
}
INIT_LIST_HEAD ( & q - > stream ) ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_queue_cancel ) ;
2007-08-23 23:26:14 +04:00
/* --------------------------------------------------------------------- */
2008-01-31 19:57:53 +03:00
/* Locking: Caller holds q->vb_lock */
2007-08-23 23:26:14 +04:00
enum v4l2_field videobuf_next_field ( struct videobuf_queue * q )
{
enum v4l2_field field = q - > field ;
BUG_ON ( V4L2_FIELD_ANY = = field ) ;
if ( V4L2_FIELD_ALTERNATE = = field ) {
if ( V4L2_FIELD_TOP = = q - > last ) {
field = V4L2_FIELD_BOTTOM ;
q - > last = V4L2_FIELD_BOTTOM ;
} else {
field = V4L2_FIELD_TOP ;
q - > last = V4L2_FIELD_TOP ;
}
}
return field ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_next_field ) ;
2007-08-23 23:26:14 +04:00
2008-01-31 19:57:53 +03:00
/* Locking: Caller holds q->vb_lock */
2007-08-23 23:26:14 +04:00
static void videobuf_status ( struct videobuf_queue * q , struct v4l2_buffer * b ,
struct videobuf_buffer * vb , enum v4l2_buf_type type )
{
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( vb - > magic , MAGIC_BUFFER ) ;
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-08-23 23:26:14 +04:00
b - > index = vb - > i ;
b - > type = type ;
b - > memory = vb - > memory ;
switch ( b - > memory ) {
case V4L2_MEMORY_MMAP :
b - > m . offset = vb - > boff ;
b - > length = vb - > bsize ;
break ;
case V4L2_MEMORY_USERPTR :
b - > m . userptr = vb - > baddr ;
b - > length = vb - > bsize ;
break ;
case V4L2_MEMORY_OVERLAY :
b - > m . offset = vb - > boff ;
break ;
2012-06-14 17:37:38 +04:00
case V4L2_MEMORY_DMABUF :
/* DMABUF is not handled in videobuf framework */
break ;
2007-08-23 23:26:14 +04:00
}
2012-10-23 00:10:16 +04:00
b - > flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC ;
2007-09-28 01:25:44 +04:00
if ( vb - > map )
2007-08-23 23:26:14 +04:00
b - > flags | = V4L2_BUF_FLAG_MAPPED ;
switch ( vb - > state ) {
2007-11-07 02:02:36 +03:00
case VIDEOBUF_PREPARED :
case VIDEOBUF_QUEUED :
case VIDEOBUF_ACTIVE :
2007-08-23 23:26:14 +04:00
b - > flags | = V4L2_BUF_FLAG_QUEUED ;
break ;
2007-11-07 02:02:36 +03:00
case VIDEOBUF_ERROR :
2010-04-28 11:05:22 +04:00
b - > flags | = V4L2_BUF_FLAG_ERROR ;
/* fall through */
case VIDEOBUF_DONE :
2007-08-23 23:26:14 +04:00
b - > flags | = V4L2_BUF_FLAG_DONE ;
break ;
2007-11-07 02:02:36 +03:00
case VIDEOBUF_NEEDS_INIT :
case VIDEOBUF_IDLE :
2007-08-23 23:26:14 +04:00
/* nothing */
break ;
}
b - > field = vb - > field ;
b - > timestamp = vb - > ts ;
b - > bytesused = vb - > size ;
b - > sequence = vb - > field_count > > 1 ;
}
2007-11-14 02:05:38 +03:00
int videobuf_mmap_free ( struct videobuf_queue * q )
{
int ret ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2010-05-11 17:36:29 +04:00
ret = __videobuf_free ( q ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-11-14 02:05:38 +03:00
return ret ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_mmap_free ) ;
2007-11-14 02:05:38 +03:00
2008-01-31 19:57:53 +03:00
/* Locking: Caller holds q->vb_lock */
2008-05-20 20:53:52 +04:00
int __videobuf_mmap_setup ( struct videobuf_queue * q ,
2007-11-14 02:05:38 +03:00
unsigned int bcount , unsigned int bsize ,
enum v4l2_memory memory )
{
unsigned int i ;
int err ;
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-11-14 02:05:38 +03:00
2010-05-11 17:36:29 +04:00
err = __videobuf_free ( q ) ;
2007-11-14 02:05:38 +03:00
if ( 0 ! = err )
return err ;
/* Allocate and initialize buffers */
for ( i = 0 ; i < bcount ; i + + ) {
2010-05-11 17:36:28 +04:00
q - > bufs [ i ] = videobuf_alloc_vb ( q ) ;
2007-11-14 02:05:38 +03:00
2010-03-17 10:01:04 +03:00
if ( NULL = = q - > bufs [ i ] )
2007-11-14 02:05:38 +03:00
break ;
q - > bufs [ i ] - > i = i ;
q - > bufs [ i ] - > memory = memory ;
q - > bufs [ i ] - > bsize = bsize ;
switch ( memory ) {
case V4L2_MEMORY_MMAP :
2009-07-23 17:56:25 +04:00
q - > bufs [ i ] - > boff = PAGE_ALIGN ( bsize ) * i ;
2007-11-14 02:05:38 +03:00
break ;
case V4L2_MEMORY_USERPTR :
case V4L2_MEMORY_OVERLAY :
2012-06-14 17:37:38 +04:00
case V4L2_MEMORY_DMABUF :
2007-11-14 02:05:38 +03:00
/* nothing */
break ;
}
}
if ( ! i )
return - ENOMEM ;
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " mmap setup: %d buffers, %d bytes each \n " , i , bsize ) ;
2007-11-14 02:05:38 +03:00
return i ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( __videobuf_mmap_setup ) ;
2007-11-14 02:05:38 +03:00
int videobuf_mmap_setup ( struct videobuf_queue * q ,
unsigned int bcount , unsigned int bsize ,
enum v4l2_memory memory )
{
int ret ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-11-14 02:05:38 +03:00
ret = __videobuf_mmap_setup ( q , bcount , bsize , memory ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-11-14 02:05:38 +03:00
return ret ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_mmap_setup ) ;
2007-11-14 02:05:38 +03:00
2007-08-23 23:26:14 +04:00
int videobuf_reqbufs ( struct videobuf_queue * q ,
struct v4l2_requestbuffers * req )
{
2007-12-10 16:53:20 +03:00
unsigned int size , count ;
2007-08-23 23:26:14 +04:00
int retval ;
if ( req - > count < 1 ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " reqbufs: count invalid (%d) \n " , req - > count ) ;
2007-08-23 23:26:14 +04:00
return - EINVAL ;
}
2007-11-14 02:05:38 +03:00
2007-08-23 23:26:14 +04:00
if ( req - > memory ! = V4L2_MEMORY_MMAP & &
req - > memory ! = V4L2_MEMORY_USERPTR & &
req - > memory ! = V4L2_MEMORY_OVERLAY ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " reqbufs: memory type invalid \n " ) ;
2007-08-23 23:26:14 +04:00
return - EINVAL ;
}
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-11-14 02:05:38 +03:00
if ( req - > type ! = q - > type ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " reqbufs: queue type invalid \n " ) ;
2007-11-14 02:05:38 +03:00
retval = - EINVAL ;
goto done ;
}
2007-08-23 23:26:14 +04:00
if ( q - > streaming ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " reqbufs: streaming already exists \n " ) ;
2007-09-28 03:55:28 +04:00
retval = - EBUSY ;
goto done ;
2007-08-23 23:26:14 +04:00
}
if ( ! list_empty ( & q - > stream ) ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " reqbufs: stream running \n " ) ;
2007-09-28 03:55:28 +04:00
retval = - EBUSY ;
goto done ;
2007-08-23 23:26:14 +04:00
}
count = req - > count ;
if ( count > VIDEO_MAX_FRAME )
count = VIDEO_MAX_FRAME ;
size = 0 ;
2007-12-10 16:53:20 +03:00
q - > ops - > buf_setup ( q , & count , & size ) ;
2009-11-23 00:03:05 +03:00
dprintk ( 1 , " reqbufs: bufs=%d, size=0x%x [%u pages total] \n " ,
count , size ,
2010-03-17 10:01:04 +03:00
( unsigned int ) ( ( count * PAGE_ALIGN ( size ) ) > > PAGE_SHIFT ) ) ;
2007-08-23 23:26:14 +04:00
2007-12-10 16:53:20 +03:00
retval = __videobuf_mmap_setup ( q , count , size , req - > memory ) ;
2007-08-23 23:26:14 +04:00
if ( retval < 0 ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " reqbufs: mmap setup returned %d \n " , retval ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2007-10-05 23:26:27 +04:00
req - > count = retval ;
2009-04-29 22:57:24 +04:00
retval = 0 ;
2007-08-23 23:26:14 +04:00
done :
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
return retval ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_reqbufs ) ;
2007-08-23 23:26:14 +04:00
int videobuf_querybuf ( struct videobuf_queue * q , struct v4l2_buffer * b )
{
2007-11-14 02:05:38 +03:00
int ret = - EINVAL ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-08-23 23:26:14 +04:00
if ( unlikely ( b - > type ! = q - > type ) ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " querybuf: Wrong type. \n " ) ;
2007-11-14 02:05:38 +03:00
goto done ;
2007-08-23 23:26:14 +04:00
}
2009-05-02 23:38:47 +04:00
if ( unlikely ( b - > index > = VIDEO_MAX_FRAME ) ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " querybuf: index out of range. \n " ) ;
2007-11-14 02:05:38 +03:00
goto done ;
2007-08-23 23:26:14 +04:00
}
if ( unlikely ( NULL = = q - > bufs [ b - > index ] ) ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " querybuf: buffer is null. \n " ) ;
2007-11-14 02:05:38 +03:00
goto done ;
2007-08-23 23:26:14 +04:00
}
2007-11-14 02:05:38 +03:00
2007-12-10 16:53:20 +03:00
videobuf_status ( q , b , q - > bufs [ b - > index ] , q - > type ) ;
2007-11-14 02:05:38 +03:00
ret = 0 ;
done :
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-11-14 02:05:38 +03:00
return ret ;
2007-08-23 23:26:14 +04:00
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_querybuf ) ;
2007-08-23 23:26:14 +04:00
2010-03-17 10:01:04 +03:00
int videobuf_qbuf ( struct videobuf_queue * q , struct v4l2_buffer * b )
2007-08-23 23:26:14 +04:00
{
struct videobuf_buffer * buf ;
enum v4l2_field field ;
2007-12-10 16:53:20 +03:00
unsigned long flags = 0 ;
2007-08-23 23:26:14 +04:00
int retval ;
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-08-23 23:26:14 +04:00
2007-09-28 03:34:09 +04:00
if ( b - > memory = = V4L2_MEMORY_MMAP )
down_read ( & current - > mm - > mmap_sem ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-08-23 23:26:14 +04:00
retval = - EBUSY ;
if ( q - > reading ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: Reading running... \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
retval = - EINVAL ;
if ( b - > type ! = q - > type ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: Wrong type. \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2009-05-02 23:38:47 +04:00
if ( b - > index > = VIDEO_MAX_FRAME ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: index out of range. \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
buf = q - > bufs [ b - > index ] ;
if ( NULL = = buf ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: buffer is null. \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( buf - > magic , MAGIC_BUFFER ) ;
2007-08-23 23:26:14 +04:00
if ( buf - > memory ! = b - > memory ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: memory type is wrong. \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2007-11-07 02:02:36 +03:00
if ( buf - > state ! = VIDEOBUF_NEEDS_INIT & & buf - > state ! = VIDEOBUF_IDLE ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: buffer is already queued or active. \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
switch ( b - > memory ) {
case V4L2_MEMORY_MMAP :
if ( 0 = = buf - > baddr ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: mmap requested "
" but buffer addr is zero! \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2010-04-21 13:44:27 +04:00
if ( q - > type = = V4L2_BUF_TYPE_VIDEO_OUTPUT
| | q - > type = = V4L2_BUF_TYPE_VBI_OUTPUT
| | q - > type = = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ) {
buf - > size = b - > bytesused ;
buf - > field = b - > field ;
buf - > ts = b - > timestamp ;
}
2007-08-23 23:26:14 +04:00
break ;
case V4L2_MEMORY_USERPTR :
if ( b - > length < buf - > bsize ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: buffer length is not enough \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2007-12-10 16:53:20 +03:00
if ( VIDEOBUF_NEEDS_INIT ! = buf - > state & &
buf - > baddr ! = b - > m . userptr )
q - > ops - > buf_release ( q , buf ) ;
2007-08-23 23:26:14 +04:00
buf - > baddr = b - > m . userptr ;
break ;
case V4L2_MEMORY_OVERLAY :
buf - > boff = b - > m . offset ;
break ;
default :
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: wrong memory type \n " ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: requesting next field \n " ) ;
2007-08-23 23:26:14 +04:00
field = videobuf_next_field ( q ) ;
2007-12-10 16:53:20 +03:00
retval = q - > ops - > buf_prepare ( q , buf , field ) ;
2007-08-23 23:26:14 +04:00
if ( 0 ! = retval ) {
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " qbuf: buffer_prepare returned %d \n " , retval ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2007-12-10 16:53:20 +03:00
list_add_tail ( & buf - > stream , & q - > stream ) ;
2007-08-23 23:26:14 +04:00
if ( q - > streaming ) {
2008-03-28 20:18:33 +03:00
spin_lock_irqsave ( q - > irqlock , flags ) ;
2007-12-10 16:53:20 +03:00
q - > ops - > buf_queue ( q , buf ) ;
2008-03-28 20:18:33 +03:00
spin_unlock_irqrestore ( q - > irqlock , flags ) ;
2007-08-23 23:26:14 +04:00
}
2010-03-13 17:47:06 +03:00
dprintk ( 1 , " qbuf: succeeded \n " ) ;
2007-08-23 23:26:14 +04:00
retval = 0 ;
2008-04-03 01:10:59 +04:00
wake_up_interruptible_sync ( & q - > wait ) ;
2007-08-23 23:26:14 +04:00
2010-03-17 10:01:04 +03:00
done :
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-09-28 03:34:09 +04:00
if ( b - > memory = = V4L2_MEMORY_MMAP )
up_read ( & current - > mm - > mmap_sem ) ;
2007-08-23 23:26:14 +04:00
return retval ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_qbuf ) ;
2008-04-03 01:10:59 +04:00
/* Locking: Caller holds q->vb_lock */
static int stream_next_buffer_check_queue ( struct videobuf_queue * q , int noblock )
2007-08-23 23:26:14 +04:00
{
int retval ;
2008-04-03 01:10:59 +04:00
checks :
if ( ! q - > streaming ) {
dprintk ( 1 , " next_buffer: Not streaming \n " ) ;
retval = - EINVAL ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2008-04-03 01:10:59 +04:00
2007-08-23 23:26:14 +04:00
if ( list_empty ( & q - > stream ) ) {
2008-04-03 01:10:59 +04:00
if ( noblock ) {
retval = - EAGAIN ;
dprintk ( 2 , " next_buffer: no buffers to dequeue \n " ) ;
goto done ;
} else {
dprintk ( 2 , " next_buffer: waiting on buffer \n " ) ;
/* Drop lock to avoid deadlock with qbuf */
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2008-04-03 01:10:59 +04:00
/* Checking list_empty and streaming is safe without
* locks because we goto checks to validate while
* holding locks before proceeding */
retval = wait_event_interruptible ( q - > wait ,
! list_empty ( & q - > stream ) | | ! q - > streaming ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2008-04-03 01:10:59 +04:00
if ( retval )
goto done ;
goto checks ;
}
2007-08-23 23:26:14 +04:00
}
2008-04-03 01:10:59 +04:00
retval = 0 ;
done :
return retval ;
}
/* Locking: Caller holds q->vb_lock */
static int stream_next_buffer ( struct videobuf_queue * q ,
struct videobuf_buffer * * vb , int nonblocking )
{
int retval ;
struct videobuf_buffer * buf = NULL ;
retval = stream_next_buffer_check_queue ( q , nonblocking ) ;
if ( retval )
goto done ;
2007-08-23 23:26:14 +04:00
buf = list_entry ( q - > stream . next , struct videobuf_buffer , stream ) ;
2010-09-26 16:01:26 +04:00
retval = videobuf_waiton ( q , buf , nonblocking , 1 ) ;
2008-04-03 01:10:59 +04:00
if ( retval < 0 )
goto done ;
* vb = buf ;
done :
return retval ;
}
int videobuf_dqbuf ( struct videobuf_queue * q ,
2010-03-17 10:01:04 +03:00
struct v4l2_buffer * b , int nonblocking )
2008-04-03 01:10:59 +04:00
{
struct videobuf_buffer * buf = NULL ;
int retval ;
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2010-04-28 11:05:22 +04:00
memset ( b , 0 , sizeof ( * b ) ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2008-04-03 01:10:59 +04:00
retval = stream_next_buffer ( q , & buf , nonblocking ) ;
2007-08-23 23:26:14 +04:00
if ( retval < 0 ) {
2008-04-03 01:10:59 +04:00
dprintk ( 1 , " dqbuf: next_buffer error: %i \n " , retval ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2008-04-03 01:10:59 +04:00
2007-08-23 23:26:14 +04:00
switch ( buf - > state ) {
2007-11-07 02:02:36 +03:00
case VIDEOBUF_ERROR :
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " dqbuf: state is error \n " ) ;
2007-08-23 23:26:14 +04:00
break ;
2007-11-07 02:02:36 +03:00
case VIDEOBUF_DONE :
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " dqbuf: state is done \n " ) ;
2007-08-23 23:26:14 +04:00
break ;
default :
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " dqbuf: state invalid \n " ) ;
2007-08-23 23:26:14 +04:00
retval = - EINVAL ;
goto done ;
}
2010-04-28 11:05:22 +04:00
CALL ( q , sync , q , buf ) ;
2007-12-10 16:53:20 +03:00
videobuf_status ( q , b , buf , q - > type ) ;
2010-04-28 11:05:22 +04:00
list_del ( & buf - > stream ) ;
buf - > state = VIDEOBUF_IDLE ;
b - > flags & = ~ V4L2_BUF_FLAG_DONE ;
2010-03-17 10:01:04 +03:00
done :
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
return retval ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_dqbuf ) ;
2007-08-23 23:26:14 +04:00
int videobuf_streamon ( struct videobuf_queue * q )
{
struct videobuf_buffer * buf ;
2007-12-10 16:53:20 +03:00
unsigned long flags = 0 ;
2007-08-23 23:26:14 +04:00
int retval ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-08-23 23:26:14 +04:00
retval = - EBUSY ;
if ( q - > reading )
goto done ;
retval = 0 ;
if ( q - > streaming )
goto done ;
q - > streaming = 1 ;
2008-03-28 20:18:33 +03:00
spin_lock_irqsave ( q - > irqlock , flags ) ;
2007-10-10 12:37:43 +04:00
list_for_each_entry ( buf , & q - > stream , stream )
2007-11-07 02:02:36 +03:00
if ( buf - > state = = VIDEOBUF_PREPARED )
2007-12-10 16:53:20 +03:00
q - > ops - > buf_queue ( q , buf ) ;
2008-03-28 20:18:33 +03:00
spin_unlock_irqrestore ( q - > irqlock , flags ) ;
2007-08-23 23:26:14 +04:00
2008-04-03 01:10:59 +04:00
wake_up_interruptible_sync ( & q - > wait ) ;
2010-03-17 10:01:04 +03:00
done :
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
return retval ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_streamon ) ;
2007-08-23 23:26:14 +04:00
2008-01-31 19:57:53 +03:00
/* Locking: Caller holds q->vb_lock */
2007-11-14 02:05:38 +03:00
static int __videobuf_streamoff ( struct videobuf_queue * q )
2007-08-23 23:26:14 +04:00
{
if ( ! q - > streaming )
2007-11-14 02:05:38 +03:00
return - EINVAL ;
2007-08-23 23:26:14 +04:00
videobuf_queue_cancel ( q ) ;
2007-11-14 02:05:38 +03:00
return 0 ;
}
int videobuf_streamoff ( struct videobuf_queue * q )
{
int retval ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-11-14 02:05:38 +03:00
retval = __videobuf_streamoff ( q ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-11-14 02:05:38 +03:00
2007-08-23 23:26:14 +04:00
return retval ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_streamoff ) ;
2007-08-23 23:26:14 +04:00
2008-01-31 19:57:53 +03:00
/* Locking: Caller holds q->vb_lock */
2007-08-23 23:26:14 +04:00
static ssize_t videobuf_read_zerocopy ( struct videobuf_queue * q ,
char __user * data ,
size_t count , loff_t * ppos )
{
enum v4l2_field field ;
2007-12-10 16:53:20 +03:00
unsigned long flags = 0 ;
2007-08-23 23:26:14 +04:00
int retval ;
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-08-23 23:26:14 +04:00
/* setup stuff */
2010-05-11 17:36:28 +04:00
q - > read_buf = videobuf_alloc_vb ( q ) ;
2007-08-23 23:26:14 +04:00
if ( NULL = = q - > read_buf )
return - ENOMEM ;
q - > read_buf - > memory = V4L2_MEMORY_USERPTR ;
q - > read_buf - > baddr = ( unsigned long ) data ;
q - > read_buf - > bsize = count ;
field = videobuf_next_field ( q ) ;
2007-12-10 16:53:20 +03:00
retval = q - > ops - > buf_prepare ( q , q - > read_buf , field ) ;
2007-08-23 23:26:14 +04:00
if ( 0 ! = retval )
goto done ;
/* start capture & wait */
2008-03-28 20:18:33 +03:00
spin_lock_irqsave ( q - > irqlock , flags ) ;
2007-12-10 16:53:20 +03:00
q - > ops - > buf_queue ( q , q - > read_buf ) ;
2008-03-28 20:18:33 +03:00
spin_unlock_irqrestore ( q - > irqlock , flags ) ;
2010-09-26 16:01:26 +04:00
retval = videobuf_waiton ( q , q - > read_buf , 0 , 0 ) ;
2007-08-23 23:26:14 +04:00
if ( 0 = = retval ) {
2007-12-10 16:53:20 +03:00
CALL ( q , sync , q , q - > read_buf ) ;
2007-11-07 02:02:36 +03:00
if ( VIDEOBUF_ERROR = = q - > read_buf - > state )
2007-08-23 23:26:14 +04:00
retval = - EIO ;
else
retval = q - > read_buf - > size ;
}
2010-03-17 10:01:04 +03:00
done :
2007-08-23 23:26:14 +04:00
/* cleanup */
2007-12-10 16:53:20 +03:00
q - > ops - > buf_release ( q , q - > read_buf ) ;
2007-08-23 23:26:14 +04:00
kfree ( q - > read_buf ) ;
q - > read_buf = NULL ;
return retval ;
}
2010-03-28 16:22:53 +04:00
static int __videobuf_copy_to_user ( struct videobuf_queue * q ,
struct videobuf_buffer * buf ,
char __user * data , size_t count ,
int nonblocking )
{
void * vaddr = CALL ( q , vaddr , buf ) ;
/* copy to userspace */
if ( count > buf - > size - q - > read_off )
count = buf - > size - q - > read_off ;
if ( copy_to_user ( data , vaddr + q - > read_off , count ) )
return - EFAULT ;
return count ;
}
static int __videobuf_copy_stream ( struct videobuf_queue * q ,
struct videobuf_buffer * buf ,
char __user * data , size_t count , size_t pos ,
int vbihack , int nonblocking )
{
unsigned int * fc = CALL ( q , vaddr , buf ) ;
if ( vbihack ) {
/* dirty, undocumented hack -- pass the frame counter
* within the last four bytes of each vbi data block .
* We need that one to maintain backward compatibility
* to all vbi decoding software out there . . . */
fc + = ( buf - > size > > 2 ) - 1 ;
* fc = buf - > field_count > > 1 ;
dprintk ( 1 , " vbihack: %d \n " , * fc ) ;
}
/* copy stuff using the common method */
count = __videobuf_copy_to_user ( q , buf , data , count , nonblocking ) ;
if ( ( count = = - EFAULT ) & & ( pos = = 0 ) )
return - EFAULT ;
return count ;
}
2007-08-23 23:26:14 +04:00
ssize_t videobuf_read_one ( struct videobuf_queue * q ,
char __user * data , size_t count , loff_t * ppos ,
int nonblocking )
{
enum v4l2_field field ;
2007-12-10 16:53:20 +03:00
unsigned long flags = 0 ;
2008-04-22 21:46:03 +04:00
unsigned size = 0 , nbufs = 1 ;
2007-08-23 23:26:14 +04:00
int retval ;
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-08-23 23:26:14 +04:00
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-08-23 23:26:14 +04:00
2007-12-10 16:53:20 +03:00
q - > ops - > buf_setup ( q , & nbufs , & size ) ;
2007-08-23 23:26:14 +04:00
if ( NULL = = q - > read_buf & &
count > = size & &
! nonblocking ) {
2007-12-10 16:53:20 +03:00
retval = videobuf_read_zerocopy ( q , data , count , ppos ) ;
2007-08-23 23:26:14 +04:00
if ( retval > = 0 | | retval = = - EIO )
/* ok, all done */
goto done ;
/* fallback to kernel bounce buffer on failures */
}
if ( NULL = = q - > read_buf ) {
/* need to capture a new frame */
retval = - ENOMEM ;
2010-05-11 17:36:28 +04:00
q - > read_buf = videobuf_alloc_vb ( q ) ;
2007-08-23 23:26:14 +04:00
2007-12-10 16:53:20 +03:00
dprintk ( 1 , " video alloc=0x%p \n " , q - > read_buf ) ;
2007-08-23 23:26:14 +04:00
if ( NULL = = q - > read_buf )
goto done ;
q - > read_buf - > memory = V4L2_MEMORY_USERPTR ;
q - > read_buf - > bsize = count ; /* preferred size */
field = videobuf_next_field ( q ) ;
2007-12-10 16:53:20 +03:00
retval = q - > ops - > buf_prepare ( q , q - > read_buf , field ) ;
2007-08-23 23:26:14 +04:00
if ( 0 ! = retval ) {
2007-12-10 16:53:20 +03:00
kfree ( q - > read_buf ) ;
2007-08-23 23:26:14 +04:00
q - > read_buf = NULL ;
goto done ;
}
2008-03-28 20:18:33 +03:00
spin_lock_irqsave ( q - > irqlock , flags ) ;
2007-12-10 16:53:20 +03:00
q - > ops - > buf_queue ( q , q - > read_buf ) ;
2008-03-28 20:18:33 +03:00
spin_unlock_irqrestore ( q - > irqlock , flags ) ;
2007-08-23 23:26:14 +04:00
q - > read_off = 0 ;
}
/* wait until capture is done */
2010-09-26 16:01:26 +04:00
retval = videobuf_waiton ( q , q - > read_buf , nonblocking , 1 ) ;
2007-08-23 23:26:14 +04:00
if ( 0 ! = retval )
goto done ;
2007-12-10 16:53:20 +03:00
CALL ( q , sync , q , q - > read_buf ) ;
2007-08-23 23:26:14 +04:00
2007-11-07 02:02:36 +03:00
if ( VIDEOBUF_ERROR = = q - > read_buf - > state ) {
2007-08-23 23:26:14 +04:00
/* catch I/O errors */
2007-12-10 16:53:20 +03:00
q - > ops - > buf_release ( q , q - > read_buf ) ;
2007-08-23 23:26:14 +04:00
kfree ( q - > read_buf ) ;
q - > read_buf = NULL ;
retval = - EIO ;
goto done ;
}
/* Copy to userspace */
2010-03-28 16:22:53 +04:00
retval = __videobuf_copy_to_user ( q , q - > read_buf , data , count , nonblocking ) ;
2007-12-10 16:53:20 +03:00
if ( retval < 0 )
2007-08-23 23:26:14 +04:00
goto done ;
q - > read_off + = retval ;
if ( q - > read_off = = q - > read_buf - > size ) {
/* all data copied, cleanup */
2007-12-10 16:53:20 +03:00
q - > ops - > buf_release ( q , q - > read_buf ) ;
2007-08-23 23:26:14 +04:00
kfree ( q - > read_buf ) ;
q - > read_buf = NULL ;
}
2010-03-17 10:01:04 +03:00
done :
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
return retval ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_read_one ) ;
2007-08-23 23:26:14 +04:00
2008-01-31 19:57:53 +03:00
/* Locking: Caller holds q->vb_lock */
2007-12-13 03:46:26 +03:00
static int __videobuf_read_start ( struct videobuf_queue * q )
2007-08-23 23:26:14 +04:00
{
enum v4l2_field field ;
2007-12-10 16:53:20 +03:00
unsigned long flags = 0 ;
2007-10-05 23:26:27 +04:00
unsigned int count = 0 , size = 0 ;
2007-08-23 23:26:14 +04:00
int err , i ;
2007-12-10 16:53:20 +03:00
q - > ops - > buf_setup ( q , & count , & size ) ;
2007-08-23 23:26:14 +04:00
if ( count < 2 )
count = 2 ;
if ( count > VIDEO_MAX_FRAME )
count = VIDEO_MAX_FRAME ;
size = PAGE_ALIGN ( size ) ;
2007-11-14 02:05:38 +03:00
err = __videobuf_mmap_setup ( q , count , size , V4L2_MEMORY_USERPTR ) ;
2007-10-05 23:26:27 +04:00
if ( err < 0 )
2007-08-23 23:26:14 +04:00
return err ;
2007-10-05 23:26:27 +04:00
count = err ;
2007-08-23 23:26:14 +04:00
for ( i = 0 ; i < count ; i + + ) {
field = videobuf_next_field ( q ) ;
2007-12-10 16:53:20 +03:00
err = q - > ops - > buf_prepare ( q , q - > bufs [ i ] , field ) ;
2007-08-23 23:26:14 +04:00
if ( err )
return err ;
list_add_tail ( & q - > bufs [ i ] - > stream , & q - > stream ) ;
}
2008-03-28 20:18:33 +03:00
spin_lock_irqsave ( q - > irqlock , flags ) ;
2007-08-23 23:26:14 +04:00
for ( i = 0 ; i < count ; i + + )
2007-12-10 16:53:20 +03:00
q - > ops - > buf_queue ( q , q - > bufs [ i ] ) ;
2008-03-28 20:18:33 +03:00
spin_unlock_irqrestore ( q - > irqlock , flags ) ;
2007-08-23 23:26:14 +04:00
q - > reading = 1 ;
return 0 ;
}
2007-11-14 02:05:38 +03:00
static void __videobuf_read_stop ( struct videobuf_queue * q )
2007-08-23 23:26:14 +04:00
{
int i ;
videobuf_queue_cancel ( q ) ;
2010-05-11 17:36:29 +04:00
__videobuf_free ( q ) ;
2007-08-23 23:26:14 +04:00
INIT_LIST_HEAD ( & q - > stream ) ;
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + ) {
if ( NULL = = q - > bufs [ i ] )
continue ;
kfree ( q - > bufs [ i ] ) ;
q - > bufs [ i ] = NULL ;
}
q - > read_buf = NULL ;
2007-11-14 02:05:38 +03:00
}
2007-11-16 05:09:30 +03:00
int videobuf_read_start ( struct videobuf_queue * q )
{
int rc ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-11-16 05:09:30 +03:00
rc = __videobuf_read_start ( q ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-11-16 05:09:30 +03:00
return rc ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_read_start ) ;
2007-11-16 05:09:30 +03:00
2007-11-14 02:05:38 +03:00
void videobuf_read_stop ( struct videobuf_queue * q )
{
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-11-14 02:05:38 +03:00
__videobuf_read_stop ( q ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-11-14 02:05:38 +03:00
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_read_stop ) ;
2007-11-14 02:05:38 +03:00
void videobuf_stop ( struct videobuf_queue * q )
{
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-11-14 02:05:38 +03:00
if ( q - > streaming )
__videobuf_streamoff ( q ) ;
if ( q - > reading )
__videobuf_read_stop ( q ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_stop ) ;
2007-11-14 02:05:38 +03:00
2007-08-23 23:26:14 +04:00
ssize_t videobuf_read_stream ( struct videobuf_queue * q ,
char __user * data , size_t count , loff_t * ppos ,
int vbihack , int nonblocking )
{
int rc , retval ;
2007-12-10 16:53:20 +03:00
unsigned long flags = 0 ;
2007-08-23 23:26:14 +04:00
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-08-23 23:26:14 +04:00
2008-04-09 06:20:00 +04:00
dprintk ( 2 , " %s \n " , __func__ ) ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-08-23 23:26:14 +04:00
retval = - EBUSY ;
if ( q - > streaming )
goto done ;
if ( ! q - > reading ) {
2007-12-12 22:44:54 +03:00
retval = __videobuf_read_start ( q ) ;
2007-08-23 23:26:14 +04:00
if ( retval < 0 )
goto done ;
}
retval = 0 ;
while ( count > 0 ) {
/* get / wait for data */
if ( NULL = = q - > read_buf ) {
q - > read_buf = list_entry ( q - > stream . next ,
struct videobuf_buffer ,
stream ) ;
list_del ( & q - > read_buf - > stream ) ;
q - > read_off = 0 ;
}
2010-09-26 16:01:26 +04:00
rc = videobuf_waiton ( q , q - > read_buf , nonblocking , 1 ) ;
2007-08-23 23:26:14 +04:00
if ( rc < 0 ) {
if ( 0 = = retval )
retval = rc ;
break ;
}
2007-11-07 02:02:36 +03:00
if ( q - > read_buf - > state = = VIDEOBUF_DONE ) {
2010-03-28 16:22:53 +04:00
rc = __videobuf_copy_stream ( q , q - > read_buf , data + retval , count ,
2007-08-23 23:26:14 +04:00
retval , vbihack , nonblocking ) ;
if ( rc < 0 ) {
retval = rc ;
break ;
}
retval + = rc ;
count - = rc ;
q - > read_off + = rc ;
} else {
/* some error */
q - > read_off = q - > read_buf - > size ;
if ( 0 = = retval )
retval = - EIO ;
}
/* requeue buffer when done with copying */
if ( q - > read_off = = q - > read_buf - > size ) {
list_add_tail ( & q - > read_buf - > stream ,
& q - > stream ) ;
2008-03-28 20:18:33 +03:00
spin_lock_irqsave ( q - > irqlock , flags ) ;
2007-12-10 16:53:20 +03:00
q - > ops - > buf_queue ( q , q - > read_buf ) ;
2008-03-28 20:18:33 +03:00
spin_unlock_irqrestore ( q - > irqlock , flags ) ;
2007-08-23 23:26:14 +04:00
q - > read_buf = NULL ;
}
if ( retval < 0 )
break ;
}
2010-03-17 10:01:04 +03:00
done :
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
return retval ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_read_stream ) ;
2007-08-23 23:26:14 +04:00
unsigned int videobuf_poll_stream ( struct file * file ,
struct videobuf_queue * q ,
poll_table * wait )
{
2011-07-13 11:03:52 +04:00
unsigned long req_events = poll_requested_events ( wait ) ;
2007-08-23 23:26:14 +04:00
struct videobuf_buffer * buf = NULL ;
unsigned int rc = 0 ;
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2007-08-23 23:26:14 +04:00
if ( q - > streaming ) {
if ( ! list_empty ( & q - > stream ) )
buf = list_entry ( q - > stream . next ,
struct videobuf_buffer , stream ) ;
2011-07-13 11:03:52 +04:00
} else if ( req_events & ( POLLIN | POLLRDNORM ) ) {
2007-08-23 23:26:14 +04:00
if ( ! q - > reading )
2007-12-12 22:44:54 +03:00
__videobuf_read_start ( q ) ;
2007-08-23 23:26:14 +04:00
if ( ! q - > reading ) {
rc = POLLERR ;
} else if ( NULL = = q - > read_buf ) {
q - > read_buf = list_entry ( q - > stream . next ,
struct videobuf_buffer ,
stream ) ;
list_del ( & q - > read_buf - > stream ) ;
q - > read_off = 0 ;
}
buf = q - > read_buf ;
}
if ( ! buf )
rc = POLLERR ;
if ( 0 = = rc ) {
poll_wait ( file , & buf - > done , wait ) ;
2007-11-07 02:02:36 +03:00
if ( buf - > state = = VIDEOBUF_DONE | |
2010-03-29 12:16:31 +04:00
buf - > state = = VIDEOBUF_ERROR ) {
switch ( q - > type ) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT :
case V4L2_BUF_TYPE_VBI_OUTPUT :
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT :
rc = POLLOUT | POLLWRNORM ;
break ;
default :
rc = POLLIN | POLLRDNORM ;
break ;
}
}
2007-08-23 23:26:14 +04:00
}
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
return rc ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_poll_stream ) ;
2007-08-23 23:26:14 +04:00
2010-03-17 10:01:04 +03:00
int videobuf_mmap_mapper ( struct videobuf_queue * q , struct vm_area_struct * vma )
2007-08-23 23:26:14 +04:00
{
2010-03-28 16:09:05 +04:00
int rc = - EINVAL ;
int i ;
2007-08-23 23:26:14 +04:00
2007-12-10 16:53:20 +03:00
MAGIC_CHECK ( q - > int_ops - > magic , MAGIC_QTYPE_OPS ) ;
2007-08-23 23:26:14 +04:00
2010-03-28 16:09:05 +04:00
if ( ! ( vma - > vm_flags & VM_WRITE ) | | ! ( vma - > vm_flags & VM_SHARED ) ) {
dprintk ( 1 , " mmap appl bug: PROT_WRITE and MAP_SHARED are required \n " ) ;
return - EINVAL ;
}
2010-09-21 00:24:30 +04:00
videobuf_queue_lock ( q ) ;
2010-03-28 16:09:05 +04:00
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + ) {
struct videobuf_buffer * buf = q - > bufs [ i ] ;
if ( buf & & buf - > memory = = V4L2_MEMORY_MMAP & &
buf - > boff = = ( vma - > vm_pgoff < < PAGE_SHIFT ) ) {
rc = CALL ( q , mmap_mapper , q , buf , vma ) ;
break ;
}
}
2010-09-21 00:24:30 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
2010-03-28 16:09:05 +04:00
return rc ;
2007-08-23 23:26:14 +04:00
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_mmap_mapper ) ;