2015-09-22 10:30:29 -03:00
/*
* videobuf2 - v4l2 . c - V4L2 driver helper framework
*
* Copyright ( C ) 2010 Samsung Electronics
*
* Author : Pawel Osciak < pawel @ osciak . com >
* Marek Szyprowski < m . szyprowski @ samsung . com >
*
* The vb2_thread implementation was based on code from videobuf - dvb . c :
* ( c ) 2004 Gerd Knorr < kraxel @ bytesex . org > [ SUSE Labs ]
*
* 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 .
*/
# include <linux/err.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/poll.h>
# include <linux/slab.h>
# include <linux/sched.h>
# include <linux/freezer.h>
# include <linux/kthread.h>
2015-10-06 06:37:49 -03:00
# include <media/v4l2-dev.h>
# include <media/v4l2-fh.h>
# include <media/v4l2-event.h>
# include <media/v4l2-common.h>
2015-09-22 10:30:29 -03:00
# include <media/videobuf2-v4l2.h>
2015-11-03 08:16:42 -02:00
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 )
2015-10-06 06:37:49 -03:00
/* Flags that are set by the vb2 core */
# define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \
V4L2_BUF_FLAG_PREPARED | \
V4L2_BUF_FLAG_TIMESTAMP_MASK )
/* Output buffer flags that should be passed on to the driver */
# define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | \
V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_TIMECODE )
/**
* __verify_planes_array ( ) - verify that the planes array passed in struct
* v4l2_buffer from userspace can be safely used
*/
static int __verify_planes_array ( struct vb2_buffer * vb , const struct v4l2_buffer * b )
{
if ( ! V4L2_TYPE_IS_MULTIPLANAR ( b - > type ) )
return 0 ;
/* Is memory for copying plane information present? */
2015-11-13 08:46:00 -02:00
if ( b - > m . planes = = NULL ) {
2015-10-06 06:37:49 -03:00
dprintk ( 1 , " multi-planar buffer passed but "
" planes array not provided \n " ) ;
return - EINVAL ;
}
if ( b - > length < vb - > num_planes | | b - > length > VB2_MAX_PLANES ) {
dprintk ( 1 , " incorrect planes array length, "
" expected %d, got %d \n " , vb - > num_planes , b - > length ) ;
return - EINVAL ;
}
return 0 ;
}
/**
* __verify_length ( ) - Verify that the bytesused value for each plane fits in
* the plane length and that the data offset doesn ' t exceed the bytesused value .
*/
static int __verify_length ( struct vb2_buffer * vb , const struct v4l2_buffer * b )
{
unsigned int length ;
unsigned int bytesused ;
unsigned int plane ;
if ( ! V4L2_TYPE_IS_OUTPUT ( b - > type ) )
return 0 ;
if ( V4L2_TYPE_IS_MULTIPLANAR ( b - > type ) ) {
for ( plane = 0 ; plane < vb - > num_planes ; + + plane ) {
length = ( b - > memory = = VB2_MEMORY_USERPTR | |
b - > memory = = VB2_MEMORY_DMABUF )
? b - > m . planes [ plane ] . length
: vb - > planes [ plane ] . length ;
bytesused = b - > m . planes [ plane ] . bytesused
? b - > m . planes [ plane ] . bytesused : length ;
if ( b - > m . planes [ plane ] . bytesused > length )
return - EINVAL ;
if ( b - > m . planes [ plane ] . data_offset > 0 & &
b - > m . planes [ plane ] . data_offset > = bytesused )
return - EINVAL ;
}
} else {
length = ( b - > memory = = VB2_MEMORY_USERPTR )
? b - > length : vb - > planes [ 0 ] . length ;
if ( b - > bytesused > length )
return - EINVAL ;
}
return 0 ;
}
2015-11-20 08:32:00 -02:00
static void __copy_timestamp ( struct vb2_buffer * vb , const void * pb )
2015-10-06 06:37:49 -03:00
{
const struct v4l2_buffer * b = pb ;
struct vb2_v4l2_buffer * vbuf = to_vb2_v4l2_buffer ( vb ) ;
struct vb2_queue * q = vb - > vb2_queue ;
if ( q - > is_output ) {
/*
* For output buffers copy the timestamp if needed ,
* and the timecode field and flag if needed .
*/
2015-11-03 08:16:38 -02:00
if ( q - > copy_timestamp )
2015-11-03 08:16:37 -02:00
vb - > timestamp = timeval_to_ns ( & b - > timestamp ) ;
2015-10-06 06:37:49 -03:00
vbuf - > flags | = b - > flags & V4L2_BUF_FLAG_TIMECODE ;
if ( b - > flags & V4L2_BUF_FLAG_TIMECODE )
vbuf - > timecode = b - > timecode ;
}
} ;
static void vb2_warn_zero_bytesused ( struct vb2_buffer * vb )
{
static bool check_once ;
if ( check_once )
return ;
check_once = true ;
WARN_ON ( 1 ) ;
pr_warn ( " use of bytesused == 0 is deprecated and will be removed in the future, \n " ) ;
if ( vb - > vb2_queue - > allow_zero_bytesused )
pr_warn ( " use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead. \n " ) ;
else
pr_warn ( " use the actual size instead. \n " ) ;
}
static int vb2_queue_or_prepare_buf ( struct vb2_queue * q , struct v4l2_buffer * b ,
const char * opname )
{
if ( b - > type ! = q - > type ) {
dprintk ( 1 , " %s: invalid buffer type \n " , opname ) ;
return - EINVAL ;
}
if ( b - > index > = q - > num_buffers ) {
dprintk ( 1 , " %s: buffer index out of range \n " , opname ) ;
return - EINVAL ;
}
if ( q - > bufs [ b - > index ] = = NULL ) {
/* Should never happen */
dprintk ( 1 , " %s: buffer is NULL \n " , opname ) ;
return - EINVAL ;
}
if ( b - > memory ! = q - > memory ) {
dprintk ( 1 , " %s: invalid memory type \n " , opname ) ;
return - EINVAL ;
}
return __verify_planes_array ( q - > bufs [ b - > index ] , b ) ;
}
/**
* __fill_v4l2_buffer ( ) - fill in a struct v4l2_buffer with information to be
* returned to userspace
*/
2015-11-20 08:32:00 -02:00
static void __fill_v4l2_buffer ( struct vb2_buffer * vb , void * pb )
2015-10-06 06:37:49 -03:00
{
struct v4l2_buffer * b = pb ;
struct vb2_v4l2_buffer * vbuf = to_vb2_v4l2_buffer ( vb ) ;
struct vb2_queue * q = vb - > vb2_queue ;
unsigned int plane ;
/* Copy back data such as timestamp, flags, etc. */
b - > index = vb - > index ;
b - > type = vb - > type ;
b - > memory = vb - > memory ;
b - > bytesused = 0 ;
b - > flags = vbuf - > flags ;
b - > field = vbuf - > field ;
2015-11-03 08:16:37 -02:00
b - > timestamp = ns_to_timeval ( vb - > timestamp ) ;
2015-10-06 06:37:49 -03:00
b - > timecode = vbuf - > timecode ;
b - > sequence = vbuf - > sequence ;
b - > reserved2 = 0 ;
b - > reserved = 0 ;
if ( q - > is_multiplanar ) {
/*
* Fill in plane - related data if userspace provided an array
* for it . The caller has already verified memory and size .
*/
b - > length = vb - > num_planes ;
for ( plane = 0 ; plane < vb - > num_planes ; + + plane ) {
struct v4l2_plane * pdst = & b - > m . planes [ plane ] ;
struct vb2_plane * psrc = & vb - > planes [ plane ] ;
pdst - > bytesused = psrc - > bytesused ;
pdst - > length = psrc - > length ;
if ( q - > memory = = VB2_MEMORY_MMAP )
pdst - > m . mem_offset = psrc - > m . offset ;
else if ( q - > memory = = VB2_MEMORY_USERPTR )
pdst - > m . userptr = psrc - > m . userptr ;
else if ( q - > memory = = VB2_MEMORY_DMABUF )
pdst - > m . fd = psrc - > m . fd ;
pdst - > data_offset = psrc - > data_offset ;
memset ( pdst - > reserved , 0 , sizeof ( pdst - > reserved ) ) ;
}
} else {
/*
* We use length and offset in v4l2_planes array even for
* single - planar buffers , but userspace does not .
*/
b - > length = vb - > planes [ 0 ] . length ;
b - > bytesused = vb - > planes [ 0 ] . bytesused ;
if ( q - > memory = = VB2_MEMORY_MMAP )
b - > m . offset = vb - > planes [ 0 ] . m . offset ;
else if ( q - > memory = = VB2_MEMORY_USERPTR )
b - > m . userptr = vb - > planes [ 0 ] . m . userptr ;
else if ( q - > memory = = VB2_MEMORY_DMABUF )
b - > m . fd = vb - > planes [ 0 ] . m . fd ;
}
/*
* Clear any buffer state related flags .
*/
b - > flags & = ~ V4L2_BUFFER_MASK_FLAGS ;
b - > flags | = q - > timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK ;
2015-11-03 08:16:38 -02:00
if ( ! q - > copy_timestamp ) {
2015-10-06 06:37:49 -03:00
/*
* For non - COPY timestamps , drop timestamp source bits
* and obtain the timestamp source from the queue .
*/
b - > flags & = ~ V4L2_BUF_FLAG_TSTAMP_SRC_MASK ;
b - > flags | = q - > timestamp_flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK ;
}
switch ( vb - > state ) {
case VB2_BUF_STATE_QUEUED :
case VB2_BUF_STATE_ACTIVE :
b - > flags | = V4L2_BUF_FLAG_QUEUED ;
break ;
case VB2_BUF_STATE_ERROR :
b - > flags | = V4L2_BUF_FLAG_ERROR ;
/* fall through */
case VB2_BUF_STATE_DONE :
b - > flags | = V4L2_BUF_FLAG_DONE ;
break ;
case VB2_BUF_STATE_PREPARED :
b - > flags | = V4L2_BUF_FLAG_PREPARED ;
break ;
case VB2_BUF_STATE_PREPARING :
case VB2_BUF_STATE_DEQUEUED :
case VB2_BUF_STATE_REQUEUEING :
/* nothing */
break ;
}
if ( vb2_buffer_in_use ( q , vb ) )
b - > flags | = V4L2_BUF_FLAG_MAPPED ;
2015-11-03 08:16:40 -02:00
if ( ! q - > is_output & &
b - > flags & V4L2_BUF_FLAG_DONE & &
b - > flags & V4L2_BUF_FLAG_LAST )
q - > last_buffer_dequeued = true ;
2015-10-06 06:37:49 -03:00
}
/**
* __fill_vb2_buffer ( ) - fill a vb2_buffer with information provided in a
* v4l2_buffer by the userspace . It also verifies that struct
* v4l2_buffer has a valid number of planes .
*/
static int __fill_vb2_buffer ( struct vb2_buffer * vb ,
const void * pb , struct vb2_plane * planes )
{
struct vb2_queue * q = vb - > vb2_queue ;
const struct v4l2_buffer * b = pb ;
struct vb2_v4l2_buffer * vbuf = to_vb2_v4l2_buffer ( vb ) ;
unsigned int plane ;
int ret ;
ret = __verify_length ( vb , b ) ;
if ( ret < 0 ) {
dprintk ( 1 , " plane parameters verification failed: %d \n " , ret ) ;
return ret ;
}
if ( b - > field = = V4L2_FIELD_ALTERNATE & & q - > is_output ) {
/*
* If the format ' s field is ALTERNATE , then the buffer ' s field
* should be either TOP or BOTTOM , not ALTERNATE since that
* makes no sense . The driver has to know whether the
* buffer represents a top or a bottom field in order to
* program any DMA correctly . Using ALTERNATE is wrong , since
* that just says that it is either a top or a bottom field ,
* but not which of the two it is .
*/
dprintk ( 1 , " the field is incorrectly set to ALTERNATE "
" for an output buffer \n " ) ;
return - EINVAL ;
}
2015-11-03 08:16:37 -02:00
vb - > timestamp = 0 ;
2015-10-06 06:37:49 -03:00
vbuf - > sequence = 0 ;
if ( V4L2_TYPE_IS_MULTIPLANAR ( b - > type ) ) {
if ( b - > memory = = VB2_MEMORY_USERPTR ) {
for ( plane = 0 ; plane < vb - > num_planes ; + + plane ) {
planes [ plane ] . m . userptr =
b - > m . planes [ plane ] . m . userptr ;
planes [ plane ] . length =
b - > m . planes [ plane ] . length ;
}
}
if ( b - > memory = = VB2_MEMORY_DMABUF ) {
for ( plane = 0 ; plane < vb - > num_planes ; + + plane ) {
planes [ plane ] . m . fd =
b - > m . planes [ plane ] . m . fd ;
planes [ plane ] . length =
b - > m . planes [ plane ] . length ;
}
}
/* Fill in driver-provided information for OUTPUT types */
if ( V4L2_TYPE_IS_OUTPUT ( b - > type ) ) {
/*
* Will have to go up to b - > length when API starts
* accepting variable number of planes .
*
* If bytesused = = 0 for the output buffer , then fall
* back to the full buffer size . In that case
* userspace clearly never bothered to set it and
* it ' s a safe assumption that they really meant to
* use the full plane sizes .
*
* Some drivers , e . g . old codec drivers , use bytesused = = 0
* as a way to indicate that streaming is finished .
* In that case , the driver should use the
* allow_zero_bytesused flag to keep old userspace
* applications working .
*/
for ( plane = 0 ; plane < vb - > num_planes ; + + plane ) {
struct vb2_plane * pdst = & planes [ plane ] ;
struct v4l2_plane * psrc = & b - > m . planes [ plane ] ;
if ( psrc - > bytesused = = 0 )
vb2_warn_zero_bytesused ( vb ) ;
if ( vb - > vb2_queue - > allow_zero_bytesused )
pdst - > bytesused = psrc - > bytesused ;
else
pdst - > bytesused = psrc - > bytesused ?
psrc - > bytesused : pdst - > length ;
pdst - > data_offset = psrc - > data_offset ;
}
}
} else {
/*
* Single - planar buffers do not use planes array ,
* so fill in relevant v4l2_buffer struct fields instead .
* In videobuf we use our internal V4l2_planes struct for
* single - planar buffers as well , for simplicity .
*
* If bytesused = = 0 for the output buffer , then fall back
* to the full buffer size as that ' s a sensible default .
*
* Some drivers , e . g . old codec drivers , use bytesused = = 0 as
* a way to indicate that streaming is finished . In that case ,
* the driver should use the allow_zero_bytesused flag to keep
* old userspace applications working .
*/
if ( b - > memory = = VB2_MEMORY_USERPTR ) {
planes [ 0 ] . m . userptr = b - > m . userptr ;
planes [ 0 ] . length = b - > length ;
}
if ( b - > memory = = VB2_MEMORY_DMABUF ) {
planes [ 0 ] . m . fd = b - > m . fd ;
planes [ 0 ] . length = b - > length ;
}
if ( V4L2_TYPE_IS_OUTPUT ( b - > type ) ) {
if ( b - > bytesused = = 0 )
vb2_warn_zero_bytesused ( vb ) ;
if ( vb - > vb2_queue - > allow_zero_bytesused )
planes [ 0 ] . bytesused = b - > bytesused ;
else
planes [ 0 ] . bytesused = b - > bytesused ?
b - > bytesused : planes [ 0 ] . length ;
} else
planes [ 0 ] . bytesused = 0 ;
}
/* Zero flags that the vb2 core handles */
vbuf - > flags = b - > flags & ~ V4L2_BUFFER_MASK_FLAGS ;
2015-11-03 08:16:38 -02:00
if ( ! vb - > vb2_queue - > copy_timestamp | | ! V4L2_TYPE_IS_OUTPUT ( b - > type ) ) {
2015-10-06 06:37:49 -03:00
/*
* Non - COPY timestamps and non - OUTPUT queues will get
* their timestamp and timestamp source flags from the
* queue .
*/
vbuf - > flags & = ~ V4L2_BUF_FLAG_TSTAMP_SRC_MASK ;
}
if ( V4L2_TYPE_IS_OUTPUT ( b - > type ) ) {
/*
* For output buffers mask out the timecode flag :
* this will be handled later in vb2_internal_qbuf ( ) .
* The ' field ' is valid metadata for this output buffer
* and so that needs to be copied here .
*/
vbuf - > flags & = ~ V4L2_BUF_FLAG_TIMECODE ;
vbuf - > field = b - > field ;
} else {
/* Zero any output buffer flags as this is a capture buffer */
vbuf - > flags & = ~ V4L2_BUFFER_OUT_FLAGS ;
}
return 0 ;
}
static const struct vb2_buf_ops v4l2_buf_ops = {
. fill_user_buffer = __fill_v4l2_buffer ,
. fill_vb2_buffer = __fill_vb2_buffer ,
2015-11-03 08:16:38 -02:00
. copy_timestamp = __copy_timestamp ,
2015-10-06 06:37:49 -03:00
} ;
/**
* vb2_querybuf ( ) - query video buffer information
* @ q : videobuf queue
* @ b : buffer struct passed from userspace to vidioc_querybuf handler
* in driver
*
* Should be called from vidioc_querybuf ioctl handler in driver .
* This function will verify the passed v4l2_buffer structure and fill the
* relevant information for the userspace .
*
* The return values from this function are intended to be directly returned
* from vidioc_querybuf handler in driver .
*/
int vb2_querybuf ( struct vb2_queue * q , struct v4l2_buffer * b )
{
struct vb2_buffer * vb ;
int ret ;
if ( b - > type ! = q - > type ) {
dprintk ( 1 , " wrong buffer type \n " ) ;
return - EINVAL ;
}
if ( b - > index > = q - > num_buffers ) {
dprintk ( 1 , " buffer index out of range \n " ) ;
return - EINVAL ;
}
vb = q - > bufs [ b - > index ] ;
ret = __verify_planes_array ( vb , b ) ;
2015-11-20 08:32:00 -02:00
if ( ! ret )
vb2_core_querybuf ( q , b - > index , b ) ;
return ret ;
2015-10-06 06:37:49 -03:00
}
EXPORT_SYMBOL ( vb2_querybuf ) ;
/**
* vb2_reqbufs ( ) - Wrapper for vb2_core_reqbufs ( ) that also verifies
* the memory and type values .
* @ q : videobuf2 queue
* @ req : struct passed from userspace to vidioc_reqbufs handler
* in driver
*/
int vb2_reqbufs ( struct vb2_queue * q , struct v4l2_requestbuffers * req )
{
int ret = vb2_verify_memory_type ( q , req - > memory , req - > type ) ;
return ret ? ret : vb2_core_reqbufs ( q , req - > memory , & req - > count ) ;
}
EXPORT_SYMBOL_GPL ( vb2_reqbufs ) ;
/**
* vb2_prepare_buf ( ) - Pass ownership of a buffer from userspace to the kernel
* @ q : videobuf2 queue
* @ b : buffer structure passed from userspace to vidioc_prepare_buf
* handler in driver
*
* Should be called from vidioc_prepare_buf ioctl handler of a driver .
* This function :
* 1 ) verifies the passed buffer ,
* 2 ) calls buf_prepare callback in the driver ( if provided ) , in which
* driver - specific buffer initialization can be performed ,
*
* The return values from this function are intended to be directly returned
* from vidioc_prepare_buf handler in driver .
*/
int vb2_prepare_buf ( struct vb2_queue * q , struct v4l2_buffer * b )
{
int ret ;
if ( vb2_fileio_is_active ( q ) ) {
dprintk ( 1 , " file io in progress \n " ) ;
return - EBUSY ;
}
ret = vb2_queue_or_prepare_buf ( q , b , " prepare_buf " ) ;
return ret ? ret : vb2_core_prepare_buf ( q , b - > index , b ) ;
}
EXPORT_SYMBOL_GPL ( vb2_prepare_buf ) ;
/**
* vb2_create_bufs ( ) - Wrapper for vb2_core_create_bufs ( ) that also verifies
* the memory and type values .
* @ q : videobuf2 queue
* @ create : creation parameters , passed from userspace to vidioc_create_bufs
* handler in driver
*/
int vb2_create_bufs ( struct vb2_queue * q , struct v4l2_create_buffers * create )
{
2015-10-28 00:50:37 -02:00
unsigned requested_planes = 1 ;
unsigned requested_sizes [ VIDEO_MAX_PLANES ] ;
struct v4l2_format * f = & create - > format ;
int ret = vb2_verify_memory_type ( q , create - > memory , f - > type ) ;
unsigned i ;
2015-10-06 06:37:49 -03:00
create - > index = q - > num_buffers ;
if ( create - > count = = 0 )
return ret ! = - EBUSY ? ret : 0 ;
2015-10-28 00:50:37 -02:00
switch ( f - > type ) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
requested_planes = f - > fmt . pix_mp . num_planes ;
if ( requested_planes = = 0 | |
requested_planes > VIDEO_MAX_PLANES )
return - EINVAL ;
for ( i = 0 ; i < requested_planes ; i + + )
requested_sizes [ i ] =
f - > fmt . pix_mp . plane_fmt [ i ] . sizeimage ;
break ;
case V4L2_BUF_TYPE_VIDEO_CAPTURE :
case V4L2_BUF_TYPE_VIDEO_OUTPUT :
requested_sizes [ 0 ] = f - > fmt . pix . sizeimage ;
break ;
case V4L2_BUF_TYPE_VBI_CAPTURE :
case V4L2_BUF_TYPE_VBI_OUTPUT :
requested_sizes [ 0 ] = f - > fmt . vbi . samples_per_line *
( f - > fmt . vbi . count [ 0 ] + f - > fmt . vbi . count [ 1 ] ) ;
break ;
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE :
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT :
requested_sizes [ 0 ] = f - > fmt . sliced . io_size ;
break ;
case V4L2_BUF_TYPE_SDR_CAPTURE :
case V4L2_BUF_TYPE_SDR_OUTPUT :
requested_sizes [ 0 ] = f - > fmt . sdr . buffersize ;
break ;
default :
return - EINVAL ;
}
for ( i = 0 ; i < requested_planes ; i + + )
if ( requested_sizes [ i ] = = 0 )
return - EINVAL ;
2015-10-06 06:37:49 -03:00
return ret ? ret : vb2_core_create_bufs ( q , create - > memory ,
2015-10-28 00:50:37 -02:00
& create - > count , requested_planes , requested_sizes ) ;
2015-10-06 06:37:49 -03:00
}
EXPORT_SYMBOL_GPL ( vb2_create_bufs ) ;
static int vb2_internal_qbuf ( struct vb2_queue * q , struct v4l2_buffer * b )
{
int ret = vb2_queue_or_prepare_buf ( q , b , " qbuf " ) ;
return ret ? ret : vb2_core_qbuf ( q , b - > index , b ) ;
}
/**
* vb2_qbuf ( ) - Queue a buffer from userspace
* @ q : videobuf2 queue
* @ b : buffer structure passed from userspace to vidioc_qbuf handler
* in driver
*
* Should be called from vidioc_qbuf ioctl handler of a driver .
* This function :
* 1 ) verifies the passed buffer ,
* 2 ) if necessary , calls buf_prepare callback in the driver ( if provided ) , in
* which driver - specific buffer initialization can be performed ,
* 3 ) if streaming is on , queues the buffer in driver by the means of buf_queue
* callback for processing .
*
* The return values from this function are intended to be directly returned
* from vidioc_qbuf handler in driver .
*/
int vb2_qbuf ( struct vb2_queue * q , struct v4l2_buffer * b )
{
if ( vb2_fileio_is_active ( q ) ) {
dprintk ( 1 , " file io in progress \n " ) ;
return - EBUSY ;
}
return vb2_internal_qbuf ( q , b ) ;
}
EXPORT_SYMBOL_GPL ( vb2_qbuf ) ;
static int vb2_internal_dqbuf ( struct vb2_queue * q , struct v4l2_buffer * b ,
bool nonblocking )
{
int ret ;
if ( b - > type ! = q - > type ) {
dprintk ( 1 , " invalid buffer type \n " ) ;
return - EINVAL ;
}
ret = vb2_core_dqbuf ( q , b , nonblocking ) ;
return ret ;
}
/**
* vb2_dqbuf ( ) - Dequeue a buffer to the userspace
* @ q : videobuf2 queue
* @ b : buffer structure passed from userspace to vidioc_dqbuf handler
* in driver
* @ nonblocking : if true , this call will not sleep waiting for a buffer if no
* buffers ready for dequeuing are present . Normally the driver
* would be passing ( file - > f_flags & O_NONBLOCK ) here
*
* Should be called from vidioc_dqbuf ioctl handler of a driver .
* This function :
* 1 ) verifies the passed buffer ,
* 2 ) calls buf_finish callback in the driver ( if provided ) , in which
* driver can perform any additional operations that may be required before
* returning the buffer to userspace , such as cache sync ,
* 3 ) the buffer struct members are filled with relevant information for
* the userspace .
*
* The return values from this function are intended to be directly returned
* from vidioc_dqbuf handler in driver .
*/
int vb2_dqbuf ( struct vb2_queue * q , struct v4l2_buffer * b , bool nonblocking )
{
if ( vb2_fileio_is_active ( q ) ) {
dprintk ( 1 , " file io in progress \n " ) ;
return - EBUSY ;
}
return vb2_internal_dqbuf ( q , b , nonblocking ) ;
}
EXPORT_SYMBOL_GPL ( vb2_dqbuf ) ;
/**
* vb2_streamon - start streaming
* @ q : videobuf2 queue
* @ type : type argument passed from userspace to vidioc_streamon handler
*
* Should be called from vidioc_streamon handler of a driver .
* This function :
* 1 ) verifies current state
* 2 ) passes any previously queued buffers to the driver and starts streaming
*
* The return values from this function are intended to be directly returned
* from vidioc_streamon handler in the driver .
*/
int vb2_streamon ( struct vb2_queue * q , enum v4l2_buf_type type )
{
if ( vb2_fileio_is_active ( q ) ) {
dprintk ( 1 , " file io in progress \n " ) ;
return - EBUSY ;
}
return vb2_core_streamon ( q , type ) ;
}
EXPORT_SYMBOL_GPL ( vb2_streamon ) ;
/**
* vb2_streamoff - stop streaming
* @ q : videobuf2 queue
* @ type : type argument passed from userspace to vidioc_streamoff handler
*
* Should be called from vidioc_streamoff handler of a driver .
* This function :
* 1 ) verifies current state ,
* 2 ) stop streaming and dequeues any queued buffers , including those previously
* passed to the driver ( after waiting for the driver to finish ) .
*
* This call can be used for pausing playback .
* The return values from this function are intended to be directly returned
* from vidioc_streamoff handler in the driver
*/
int vb2_streamoff ( struct vb2_queue * q , enum v4l2_buf_type type )
{
if ( vb2_fileio_is_active ( q ) ) {
dprintk ( 1 , " file io in progress \n " ) ;
return - EBUSY ;
}
return vb2_core_streamoff ( q , type ) ;
}
EXPORT_SYMBOL_GPL ( vb2_streamoff ) ;
/**
* vb2_expbuf ( ) - Export a buffer as a file descriptor
* @ q : videobuf2 queue
* @ eb : export buffer structure passed from userspace to vidioc_expbuf
* handler in driver
*
* The return values from this function are intended to be directly returned
* from vidioc_expbuf handler in driver .
*/
int vb2_expbuf ( struct vb2_queue * q , struct v4l2_exportbuffer * eb )
{
return vb2_core_expbuf ( q , & eb - > fd , eb - > type , eb - > index ,
eb - > plane , eb - > flags ) ;
}
EXPORT_SYMBOL_GPL ( vb2_expbuf ) ;
/**
* vb2_queue_init ( ) - initialize a videobuf2 queue
* @ q : videobuf2 queue ; this structure should be allocated in driver
*
* The vb2_queue structure should be allocated by the driver . The driver is
* responsible of clearing it ' s content and setting initial values for some
* required entries before calling this function .
* q - > ops , q - > mem_ops , q - > type and q - > io_modes are mandatory . Please refer
* to the struct vb2_queue description in include / media / videobuf2 - core . h
* for more information .
*/
int vb2_queue_init ( struct vb2_queue * q )
{
/*
* Sanity check
*/
if ( WARN_ON ( ! q ) | |
WARN_ON ( q - > timestamp_flags &
~ ( V4L2_BUF_FLAG_TIMESTAMP_MASK |
V4L2_BUF_FLAG_TSTAMP_SRC_MASK ) ) )
return - EINVAL ;
/* Warn that the driver should choose an appropriate timestamp type */
WARN_ON ( ( q - > timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK ) = =
V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN ) ;
/* Warn that vb2_memory should match with v4l2_memory */
if ( WARN_ON ( VB2_MEMORY_MMAP ! = ( int ) V4L2_MEMORY_MMAP )
| | WARN_ON ( VB2_MEMORY_USERPTR ! = ( int ) V4L2_MEMORY_USERPTR )
| | WARN_ON ( VB2_MEMORY_DMABUF ! = ( int ) V4L2_MEMORY_DMABUF ) )
return - EINVAL ;
if ( q - > buf_struct_size = = 0 )
q - > buf_struct_size = sizeof ( struct vb2_v4l2_buffer ) ;
q - > buf_ops = & v4l2_buf_ops ;
q - > is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR ( q - > type ) ;
q - > is_output = V4L2_TYPE_IS_OUTPUT ( q - > type ) ;
2015-11-03 08:16:38 -02:00
q - > copy_timestamp = ( q - > timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK )
= = V4L2_BUF_FLAG_TIMESTAMP_COPY ;
2015-10-06 06:37:49 -03:00
return vb2_core_queue_init ( q ) ;
}
EXPORT_SYMBOL_GPL ( vb2_queue_init ) ;
/**
* vb2_queue_release ( ) - stop streaming , release the queue and free memory
* @ q : videobuf2 queue
*
* This function stops streaming and performs necessary clean ups , including
* freeing video buffer memory . The driver is responsible for freeing
* the vb2_queue structure itself .
*/
void vb2_queue_release ( struct vb2_queue * q )
{
vb2_core_queue_release ( q ) ;
}
EXPORT_SYMBOL_GPL ( vb2_queue_release ) ;
2015-11-03 08:16:39 -02:00
/**
* vb2_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 .
*
* If the driver uses struct v4l2_fh , then vb2_poll ( ) will also check for any
* pending events .
*
* The return values from this function are intended to be directly returned
* from poll handler in driver .
*/
unsigned int vb2_poll ( struct vb2_queue * q , struct file * file , poll_table * wait )
{
struct video_device * vfd = video_devdata ( file ) ;
unsigned long req_events = poll_requested_events ( wait ) ;
unsigned int res = 0 ;
if ( test_bit ( V4L2_FL_USES_V4L2_FH , & vfd - > flags ) ) {
struct v4l2_fh * fh = file - > private_data ;
if ( v4l2_event_pending ( fh ) )
res = POLLPRI ;
else if ( req_events & POLLPRI )
poll_wait ( file , & fh - > wait , wait ) ;
2015-10-06 06:37:49 -03:00
}
2015-11-03 08:16:39 -02:00
/*
* For compatibility with vb1 : if QBUF hasn ' t been called yet , then
* return POLLERR as well . This only affects capture queues , output
* queues will always initialize waiting_for_buffers to false .
*/
if ( q - > waiting_for_buffers & & ( req_events & ( POLLIN | POLLRDNORM ) ) )
return POLLERR ;
return res | vb2_core_poll ( q , file , wait ) ;
2015-10-06 06:37:49 -03:00
}
EXPORT_SYMBOL_GPL ( vb2_poll ) ;
/*
* 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
* and struct vb2_ops .
* They contain boilerplate code that most if not all drivers have to do
* and so they simplify the driver code .
*/
/* The queue is busy if there is a owner and you are not that owner. */
static inline bool vb2_queue_is_busy ( struct video_device * vdev , struct file * file )
{
return vdev - > queue - > owner & & vdev - > queue - > owner ! = file - > private_data ;
}
/* vb2 ioctl helpers */
int vb2_ioctl_reqbufs ( struct file * file , void * priv ,
struct v4l2_requestbuffers * p )
{
struct video_device * vdev = video_devdata ( file ) ;
int res = vb2_verify_memory_type ( vdev - > queue , p - > memory , p - > type ) ;
if ( res )
return res ;
if ( vb2_queue_is_busy ( vdev , file ) )
return - EBUSY ;
res = vb2_core_reqbufs ( vdev - > queue , p - > memory , & p - > count ) ;
/* If count == 0, then the owner has released all buffers and he
is no longer owner of the queue . Otherwise we have a new owner . */
if ( res = = 0 )
vdev - > queue - > owner = p - > count ? file - > private_data : NULL ;
return res ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_reqbufs ) ;
int vb2_ioctl_create_bufs ( struct file * file , void * priv ,
struct v4l2_create_buffers * p )
{
struct video_device * vdev = video_devdata ( file ) ;
int res = vb2_verify_memory_type ( vdev - > queue , p - > memory ,
p - > format . type ) ;
p - > index = vdev - > queue - > num_buffers ;
/*
* If count = = 0 , then just check if memory and type are valid .
* Any - EBUSY result from vb2_verify_memory_type can be mapped to 0.
*/
if ( p - > count = = 0 )
return res ! = - EBUSY ? res : 0 ;
if ( res )
return res ;
if ( vb2_queue_is_busy ( vdev , file ) )
return - EBUSY ;
2015-10-28 00:50:37 -02:00
res = vb2_create_bufs ( vdev - > queue , p ) ;
2015-10-06 06:37:49 -03:00
if ( res = = 0 )
vdev - > queue - > owner = file - > private_data ;
return res ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_create_bufs ) ;
int vb2_ioctl_prepare_buf ( struct file * file , void * priv ,
struct v4l2_buffer * p )
{
struct video_device * vdev = video_devdata ( file ) ;
if ( vb2_queue_is_busy ( vdev , file ) )
return - EBUSY ;
return vb2_prepare_buf ( vdev - > queue , p ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_prepare_buf ) ;
int vb2_ioctl_querybuf ( struct file * file , void * priv , struct v4l2_buffer * p )
{
struct video_device * vdev = video_devdata ( file ) ;
/* No need to call vb2_queue_is_busy(), anyone can query buffers. */
return vb2_querybuf ( vdev - > queue , p ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_querybuf ) ;
int vb2_ioctl_qbuf ( struct file * file , void * priv , struct v4l2_buffer * p )
{
struct video_device * vdev = video_devdata ( file ) ;
if ( vb2_queue_is_busy ( vdev , file ) )
return - EBUSY ;
return vb2_qbuf ( vdev - > queue , p ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_qbuf ) ;
int vb2_ioctl_dqbuf ( struct file * file , void * priv , struct v4l2_buffer * p )
{
struct video_device * vdev = video_devdata ( file ) ;
if ( vb2_queue_is_busy ( vdev , file ) )
return - EBUSY ;
return vb2_dqbuf ( vdev - > queue , p , file - > f_flags & O_NONBLOCK ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_dqbuf ) ;
int vb2_ioctl_streamon ( struct file * file , void * priv , enum v4l2_buf_type i )
{
struct video_device * vdev = video_devdata ( file ) ;
if ( vb2_queue_is_busy ( vdev , file ) )
return - EBUSY ;
return vb2_streamon ( vdev - > queue , i ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_streamon ) ;
int vb2_ioctl_streamoff ( struct file * file , void * priv , enum v4l2_buf_type i )
{
struct video_device * vdev = video_devdata ( file ) ;
if ( vb2_queue_is_busy ( vdev , file ) )
return - EBUSY ;
return vb2_streamoff ( vdev - > queue , i ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_streamoff ) ;
int vb2_ioctl_expbuf ( struct file * file , void * priv , struct v4l2_exportbuffer * p )
{
struct video_device * vdev = video_devdata ( file ) ;
if ( vb2_queue_is_busy ( vdev , file ) )
return - EBUSY ;
return vb2_expbuf ( vdev - > queue , p ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ioctl_expbuf ) ;
/* v4l2_file_operations helpers */
int vb2_fop_mmap ( struct file * file , struct vm_area_struct * vma )
{
struct video_device * vdev = video_devdata ( file ) ;
return vb2_mmap ( vdev - > queue , vma ) ;
}
EXPORT_SYMBOL_GPL ( vb2_fop_mmap ) ;
int _vb2_fop_release ( struct file * file , struct mutex * lock )
{
struct video_device * vdev = video_devdata ( file ) ;
if ( lock )
mutex_lock ( lock ) ;
if ( file - > private_data = = vdev - > queue - > owner ) {
vb2_queue_release ( vdev - > queue ) ;
vdev - > queue - > owner = NULL ;
}
if ( lock )
mutex_unlock ( lock ) ;
return v4l2_fh_release ( file ) ;
}
EXPORT_SYMBOL_GPL ( _vb2_fop_release ) ;
int vb2_fop_release ( struct file * file )
{
struct video_device * vdev = video_devdata ( file ) ;
struct mutex * lock = vdev - > queue - > lock ? vdev - > queue - > lock : vdev - > lock ;
return _vb2_fop_release ( file , lock ) ;
}
EXPORT_SYMBOL_GPL ( vb2_fop_release ) ;
ssize_t vb2_fop_write ( struct file * file , const char __user * buf ,
size_t count , loff_t * ppos )
{
struct video_device * vdev = video_devdata ( file ) ;
struct mutex * lock = vdev - > queue - > lock ? vdev - > queue - > lock : vdev - > lock ;
int err = - EBUSY ;
if ( ! ( vdev - > queue - > io_modes & VB2_WRITE ) )
return - EINVAL ;
if ( lock & & mutex_lock_interruptible ( lock ) )
return - ERESTARTSYS ;
if ( vb2_queue_is_busy ( vdev , file ) )
goto exit ;
err = vb2_write ( vdev - > queue , buf , count , ppos ,
file - > f_flags & O_NONBLOCK ) ;
if ( vdev - > queue - > fileio )
vdev - > queue - > owner = file - > private_data ;
exit :
if ( lock )
mutex_unlock ( lock ) ;
return err ;
}
EXPORT_SYMBOL_GPL ( vb2_fop_write ) ;
ssize_t vb2_fop_read ( struct file * file , char __user * buf ,
size_t count , loff_t * ppos )
{
struct video_device * vdev = video_devdata ( file ) ;
struct mutex * lock = vdev - > queue - > lock ? vdev - > queue - > lock : vdev - > lock ;
int err = - EBUSY ;
if ( ! ( vdev - > queue - > io_modes & VB2_READ ) )
return - EINVAL ;
if ( lock & & mutex_lock_interruptible ( lock ) )
return - ERESTARTSYS ;
if ( vb2_queue_is_busy ( vdev , file ) )
goto exit ;
err = vb2_read ( vdev - > queue , buf , count , ppos ,
file - > f_flags & O_NONBLOCK ) ;
if ( vdev - > queue - > fileio )
vdev - > queue - > owner = file - > private_data ;
exit :
if ( lock )
mutex_unlock ( lock ) ;
return err ;
}
EXPORT_SYMBOL_GPL ( vb2_fop_read ) ;
unsigned int vb2_fop_poll ( struct file * file , poll_table * wait )
{
struct video_device * vdev = video_devdata ( file ) ;
struct vb2_queue * q = vdev - > queue ;
struct mutex * lock = q - > lock ? q - > lock : vdev - > lock ;
unsigned res ;
void * fileio ;
/*
* If this helper doesn ' t know how to lock , then you shouldn ' t be using
* it but you should write your own .
*/
WARN_ON ( ! lock ) ;
if ( lock & & mutex_lock_interruptible ( lock ) )
return POLLERR ;
fileio = q - > fileio ;
res = vb2_poll ( vdev - > queue , file , wait ) ;
/* If fileio was started, then we have a new queue owner. */
if ( ! fileio & & q - > fileio )
q - > owner = file - > private_data ;
if ( lock )
mutex_unlock ( lock ) ;
return res ;
}
EXPORT_SYMBOL_GPL ( vb2_fop_poll ) ;
# ifndef CONFIG_MMU
unsigned long vb2_fop_get_unmapped_area ( struct file * file , unsigned long addr ,
unsigned long len , unsigned long pgoff , unsigned long flags )
{
struct video_device * vdev = video_devdata ( file ) ;
return vb2_get_unmapped_area ( vdev - > queue , addr , len , pgoff , flags ) ;
}
EXPORT_SYMBOL_GPL ( vb2_fop_get_unmapped_area ) ;
# endif
/* vb2_ops helpers. Only use if vq->lock is non-NULL. */
void vb2_ops_wait_prepare ( struct vb2_queue * vq )
{
mutex_unlock ( vq - > lock ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ops_wait_prepare ) ;
void vb2_ops_wait_finish ( struct vb2_queue * vq )
{
mutex_lock ( vq - > lock ) ;
}
EXPORT_SYMBOL_GPL ( vb2_ops_wait_finish ) ;
2015-09-22 10:30:29 -03:00
MODULE_DESCRIPTION ( " Driver helper framework for Video for Linux 2 " ) ;
MODULE_AUTHOR ( " Pawel Osciak <pawel@osciak.com>, Marek Szyprowski " ) ;
MODULE_LICENSE ( " GPL " ) ;