2019-05-22 10:51:30 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
* Video for Linux Two
*
* A generic video device interface for the LINUX operating system
* using a set of device structures / vectors for low level operations .
*
* This file replaces the videodev . c file that comes with the
* regular kernel distribution .
*
2007-01-09 17:20:59 +03:00
* Author : Bill Dirks < bill @ thedirks . org >
2005-04-17 02:20:36 +04:00
* based on code by Alan Cox , < alan @ cymru . net >
*/
/*
* Video capture interface for Linux
*
* A generic video device interface for the LINUX operating system
* using a set of device structures / vectors for low level operations .
*
2008-10-27 21:13:47 +03:00
* Author : Alan Cox , < alan @ lxorguk . ukuu . org . uk >
2005-04-17 02:20:36 +04:00
*
* Fixes :
*/
/*
* Video4linux 1 / 2 integration by Justin Schoeman
* < justin @ suntiger . ee . up . ac . za >
* 2.4 PROCFS support ported from 2.4 kernels by
2007-10-20 01:21:04 +04:00
* Iñaki García Etxebarria < garetxe @ euskalnet . net >
2005-04-17 02:20:36 +04:00
* Makefile fix by " W. Michael Petullo " < mike @ flyn . org >
* 2.4 devfs support ported from 2.4 kernels by
* Dan Merillat < dan @ merillat . org >
* Added Gerd Knorrs v4l1 enhancements ( Justin Schoeman )
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/string.h>
# include <linux/errno.h>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <asm/div64.h>
2006-01-09 20:32:31 +03:00
# include <media/v4l2-common.h>
2008-11-23 18:19:45 +03:00
# include <media/v4l2-device.h>
2010-08-01 21:32:42 +04:00
# include <media/v4l2-ctrls.h>
2005-04-17 02:20:36 +04:00
2008-07-25 12:32:50 +04:00
# include <linux/videodev2.h>
2005-04-17 02:20:36 +04:00
/*
*
* V 4 L 2 D R I V E R H E L P E R A P I
*
*/
/*
* Video Standard Operations ( contributed by Michael Schimek )
*/
2006-06-18 21:11:08 +04:00
/* Helper functions for control handling */
2008-08-08 14:55:00 +04:00
/* Fill in a struct v4l2_queryctrl */
2014-04-16 16:41:25 +04:00
int v4l2_ctrl_query_fill ( struct v4l2_queryctrl * qctrl , s32 _min , s32 _max , s32 _step , s32 _def )
2008-08-08 14:55:00 +04:00
{
2010-08-01 21:32:42 +04:00
const char * name ;
2014-04-16 16:41:25 +04:00
s64 min = _min ;
s64 max = _max ;
u64 step = _step ;
s64 def = _def ;
2010-08-01 21:32:42 +04:00
v4l2_ctrl_fill ( qctrl - > id , & name , & qctrl - > type ,
& min , & max , & step , & def , & qctrl - > flags ) ;
2008-08-08 14:55:00 +04:00
if ( name = = NULL )
return - EINVAL ;
2006-06-18 21:11:08 +04:00
qctrl - > minimum = min ;
qctrl - > maximum = max ;
qctrl - > step = step ;
qctrl - > default_value = def ;
qctrl - > reserved [ 0 ] = qctrl - > reserved [ 1 ] = 0 ;
2018-09-10 15:19:14 +03:00
strscpy ( qctrl - > name , name , sizeof ( qctrl - > name ) ) ;
2006-06-18 21:11:08 +04:00
return 0 ;
}
2008-02-02 17:25:31 +03:00
EXPORT_SYMBOL ( v4l2_ctrl_query_fill ) ;
2006-06-18 21:11:08 +04:00
2009-05-31 04:45:46 +04:00
/* Clamp x to be between min and max, aligned to a multiple of 2^align. min
* and max don ' t have to be aligned , but there must be at least one valid
* value . E . g . , min = 17 , max = 31 , align = 4 is not allowed as there are no multiples
* of 16 between 17 and 31. */
static unsigned int clamp_align ( unsigned int x , unsigned int min ,
unsigned int max , unsigned int align )
{
/* Bits that must be zero to be aligned */
unsigned int mask = ~ ( ( 1 < < align ) - 1 ) ;
2014-09-15 12:14:48 +04:00
/* Clamp to aligned min and max */
x = clamp ( x , ( min + ~ mask ) & mask , max & mask ) ;
2009-05-31 04:45:46 +04:00
/* Round to nearest aligned value */
if ( align )
x = ( x + ( 1 < < ( align - 1 ) ) ) & mask ;
return x ;
}
2019-05-28 20:02:18 +03:00
static unsigned int clamp_roundup ( unsigned int x , unsigned int min ,
unsigned int max , unsigned int alignment )
{
x = clamp ( x , min , max ) ;
if ( alignment )
x = round_up ( x , alignment ) ;
return x ;
}
2009-05-31 04:45:46 +04:00
void v4l_bound_align_image ( u32 * w , unsigned int wmin , unsigned int wmax ,
unsigned int walign ,
u32 * h , unsigned int hmin , unsigned int hmax ,
unsigned int halign , unsigned int salign )
{
* w = clamp_align ( * w , wmin , wmax , walign ) ;
* h = clamp_align ( * h , hmin , hmax , halign ) ;
/* Usually we don't need to align the size and are done now. */
if ( ! salign )
return ;
/* How much alignment do we have? */
walign = __ffs ( * w ) ;
halign = __ffs ( * h ) ;
/* Enough to satisfy the image alignment? */
if ( walign + halign < salign ) {
/* Max walign where there is still a valid width */
unsigned int wmaxa = __fls ( wmax ^ ( wmin - 1 ) ) ;
/* Max halign where there is still a valid height */
unsigned int hmaxa = __fls ( hmax ^ ( hmin - 1 ) ) ;
/* up the smaller alignment until we have enough */
do {
if ( halign > = hmaxa | |
( walign < = halign & & walign < wmaxa ) ) {
* w = clamp_align ( * w , wmin , wmax , walign + 1 ) ;
walign = __ffs ( * w ) ;
} else {
* h = clamp_align ( * h , hmin , hmax , halign + 1 ) ;
halign = __ffs ( * h ) ;
}
} while ( halign + walign < salign ) ;
}
}
EXPORT_SYMBOL_GPL ( v4l_bound_align_image ) ;
2009-12-10 10:39:47 +03:00
2018-02-23 12:50:14 +03:00
const void *
__v4l2_find_nearest_size ( const void * array , size_t array_size ,
size_t entry_size , size_t width_offset ,
size_t height_offset , s32 width , s32 height )
{
u32 error , min_error = U32_MAX ;
const void * best = NULL ;
unsigned int i ;
if ( ! array )
return NULL ;
for ( i = 0 ; i < array_size ; i + + , array + = entry_size ) {
const u32 * entry_width = array + width_offset ;
const u32 * entry_height = array + height_offset ;
error = abs ( * entry_width - width ) + abs ( * entry_height - height ) ;
if ( error > min_error )
continue ;
min_error = error ;
best = array ;
if ( ! error )
break ;
}
return best ;
}
EXPORT_SYMBOL_GPL ( __v4l2_find_nearest_size ) ;
2018-01-22 11:58:36 +03:00
int v4l2_g_parm_cap ( struct video_device * vdev ,
struct v4l2_subdev * sd , struct v4l2_streamparm * a )
{
struct v4l2_subdev_frame_interval ival = { 0 } ;
int ret ;
if ( a - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE & &
a - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE )
return - EINVAL ;
if ( vdev - > device_caps & V4L2_CAP_READWRITE )
a - > parm . capture . readbuffers = 2 ;
if ( v4l2_subdev_has_op ( sd , video , g_frame_interval ) )
a - > parm . capture . capability = V4L2_CAP_TIMEPERFRAME ;
ret = v4l2_subdev_call ( sd , video , g_frame_interval , & ival ) ;
if ( ! ret )
a - > parm . capture . timeperframe = ival . interval ;
return ret ;
}
EXPORT_SYMBOL_GPL ( v4l2_g_parm_cap ) ;
int v4l2_s_parm_cap ( struct video_device * vdev ,
struct v4l2_subdev * sd , struct v4l2_streamparm * a )
{
struct v4l2_subdev_frame_interval ival = {
. interval = a - > parm . capture . timeperframe
} ;
int ret ;
if ( a - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE & &
a - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE )
return - EINVAL ;
memset ( & a - > parm , 0 , sizeof ( a - > parm ) ) ;
if ( vdev - > device_caps & V4L2_CAP_READWRITE )
a - > parm . capture . readbuffers = 2 ;
else
a - > parm . capture . readbuffers = 0 ;
if ( v4l2_subdev_has_op ( sd , video , g_frame_interval ) )
a - > parm . capture . capability = V4L2_CAP_TIMEPERFRAME ;
ret = v4l2_subdev_call ( sd , video , s_frame_interval , & ival ) ;
if ( ! ret )
a - > parm . capture . timeperframe = ival . interval ;
return ret ;
}
EXPORT_SYMBOL_GPL ( v4l2_s_parm_cap ) ;
2019-03-28 21:07:04 +03:00
const struct v4l2_format_info * v4l2_format_info ( u32 format )
{
static const struct v4l2_format_info formats [ ] = {
/* RGB formats */
2019-10-07 18:10:07 +03:00
{ . format = V4L2_PIX_FMT_BGR24 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 3 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_RGB24 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 3 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_HSV24 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 3 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_BGR32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_XBGR32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_BGRX32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_RGB32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_XRGB32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_RGBX32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_HSV32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_ARGB32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_RGBA32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_ABGR32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_BGRA32 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
2019-10-07 18:10:08 +03:00
{ . format = V4L2_PIX_FMT_RGB565 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_RGB555 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
2020-03-16 10:01:23 +03:00
{ . format = V4L2_PIX_FMT_BGR666 , . pixel_enc = V4L2_PIXEL_ENC_RGB , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 4 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
2019-03-28 21:07:04 +03:00
/* YUV packed formats */
2019-10-07 18:10:07 +03:00
{ . format = V4L2_PIX_FMT_YUYV , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_YVYU , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_UYVY , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_VYUY , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
2019-03-28 21:07:04 +03:00
/* YUV planar formats */
2019-10-07 18:10:07 +03:00
{ . format = V4L2_PIX_FMT_NV12 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
{ . format = V4L2_PIX_FMT_NV21 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
{ . format = V4L2_PIX_FMT_NV16 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_NV61 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_NV24 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_NV42 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_YUV410 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 4 , . vdiv = 4 } ,
{ . format = V4L2_PIX_FMT_YVU410 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 4 , . vdiv = 4 } ,
{ . format = V4L2_PIX_FMT_YUV411P , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 4 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_YUV420 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
{ . format = V4L2_PIX_FMT_YVU420 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
{ . format = V4L2_PIX_FMT_YUV422P , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
2020-03-23 20:36:18 +03:00
{ . format = V4L2_PIX_FMT_GREY , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
2019-03-28 21:07:04 +03:00
2021-08-05 05:47:51 +03:00
/* Tiled YUV formats */
{ . format = V4L2_PIX_FMT_NV12_4L4 , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 1 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
2019-03-28 21:07:04 +03:00
/* YUV planar formats, non contiguous variant */
2019-10-07 18:10:07 +03:00
{ . format = V4L2_PIX_FMT_YUV420M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 3 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
{ . format = V4L2_PIX_FMT_YVU420M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 3 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
{ . format = V4L2_PIX_FMT_YUV422M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 3 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_YVU422M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 3 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_YUV444M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 3 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_YVU444M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 3 , . comp_planes = 3 , . bpp = { 1 , 1 , 1 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_NV12M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 2 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
{ . format = V4L2_PIX_FMT_NV21M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 2 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 2 } ,
{ . format = V4L2_PIX_FMT_NV16M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 2 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_NV61M , . pixel_enc = V4L2_PIXEL_ENC_YUV , . mem_planes = 2 , . comp_planes = 2 , . bpp = { 1 , 2 , 0 , 0 } , . hdiv = 2 , . vdiv = 1 } ,
2019-03-07 01:42:40 +03:00
/* Bayer RGB formats */
2019-10-07 18:10:07 +03:00
{ . format = V4L2_PIX_FMT_SBGGR8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGBRG8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGRBG8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SRGGB8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SBGGR10 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGBRG10 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGRBG10 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SRGGB10 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SBGGR10ALAW8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGBRG10ALAW8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGRBG10ALAW8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SRGGB10ALAW8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SBGGR10DPCM8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGBRG10DPCM8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGRBG10DPCM8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SRGGB10DPCM8 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 1 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SBGGR12 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGBRG12 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SGRBG12 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
{ . format = V4L2_PIX_FMT_SRGGB12 , . pixel_enc = V4L2_PIXEL_ENC_BAYER , . mem_planes = 1 , . comp_planes = 1 , . bpp = { 2 , 0 , 0 , 0 } , . hdiv = 1 , . vdiv = 1 } ,
2019-03-28 21:07:04 +03:00
} ;
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( formats ) ; + + i )
if ( formats [ i ] . format = = format )
return & formats [ i ] ;
return NULL ;
}
EXPORT_SYMBOL ( v4l2_format_info ) ;
static inline unsigned int v4l2_format_block_width ( const struct v4l2_format_info * info , int plane )
{
if ( ! info - > block_w [ plane ] )
return 1 ;
return info - > block_w [ plane ] ;
}
static inline unsigned int v4l2_format_block_height ( const struct v4l2_format_info * info , int plane )
{
if ( ! info - > block_h [ plane ] )
return 1 ;
return info - > block_h [ plane ] ;
}
2019-05-28 20:02:18 +03:00
void v4l2_apply_frmsize_constraints ( u32 * width , u32 * height ,
const struct v4l2_frmsize_stepwise * frmsize )
{
if ( ! frmsize )
return ;
/*
* Clamp width / height to meet min / max constraints and round it up to
* macroblock alignment .
*/
* width = clamp_roundup ( * width , frmsize - > min_width , frmsize - > max_width ,
frmsize - > step_width ) ;
* height = clamp_roundup ( * height , frmsize - > min_height , frmsize - > max_height ,
frmsize - > step_height ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_apply_frmsize_constraints ) ;
2019-03-28 21:07:04 +03:00
int v4l2_fill_pixfmt_mp ( struct v4l2_pix_format_mplane * pixfmt ,
2019-05-28 20:02:17 +03:00
u32 pixelformat , u32 width , u32 height )
2019-03-28 21:07:04 +03:00
{
const struct v4l2_format_info * info ;
struct v4l2_plane_pix_format * plane ;
int i ;
info = v4l2_format_info ( pixelformat ) ;
if ( ! info )
return - EINVAL ;
pixfmt - > width = width ;
pixfmt - > height = height ;
pixfmt - > pixelformat = pixelformat ;
pixfmt - > num_planes = info - > mem_planes ;
if ( info - > mem_planes = = 1 ) {
plane = & pixfmt - > plane_fmt [ 0 ] ;
plane - > bytesperline = ALIGN ( width , v4l2_format_block_width ( info , 0 ) ) * info - > bpp [ 0 ] ;
plane - > sizeimage = 0 ;
for ( i = 0 ; i < info - > comp_planes ; i + + ) {
unsigned int hdiv = ( i = = 0 ) ? 1 : info - > hdiv ;
unsigned int vdiv = ( i = = 0 ) ? 1 : info - > vdiv ;
unsigned int aligned_width ;
unsigned int aligned_height ;
aligned_width = ALIGN ( width , v4l2_format_block_width ( info , i ) ) ;
aligned_height = ALIGN ( height , v4l2_format_block_height ( info , i ) ) ;
plane - > sizeimage + = info - > bpp [ i ] *
DIV_ROUND_UP ( aligned_width , hdiv ) *
DIV_ROUND_UP ( aligned_height , vdiv ) ;
}
} else {
for ( i = 0 ; i < info - > comp_planes ; i + + ) {
unsigned int hdiv = ( i = = 0 ) ? 1 : info - > hdiv ;
unsigned int vdiv = ( i = = 0 ) ? 1 : info - > vdiv ;
unsigned int aligned_width ;
unsigned int aligned_height ;
aligned_width = ALIGN ( width , v4l2_format_block_width ( info , i ) ) ;
aligned_height = ALIGN ( height , v4l2_format_block_height ( info , i ) ) ;
plane = & pixfmt - > plane_fmt [ i ] ;
plane - > bytesperline =
info - > bpp [ i ] * DIV_ROUND_UP ( aligned_width , hdiv ) ;
plane - > sizeimage =
plane - > bytesperline * DIV_ROUND_UP ( aligned_height , vdiv ) ;
}
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l2_fill_pixfmt_mp ) ;
2019-05-28 20:02:17 +03:00
int v4l2_fill_pixfmt ( struct v4l2_pix_format * pixfmt , u32 pixelformat ,
u32 width , u32 height )
2019-03-28 21:07:04 +03:00
{
const struct v4l2_format_info * info ;
int i ;
info = v4l2_format_info ( pixelformat ) ;
if ( ! info )
return - EINVAL ;
/* Single planar API cannot be used for multi plane formats. */
if ( info - > mem_planes > 1 )
return - EINVAL ;
pixfmt - > width = width ;
pixfmt - > height = height ;
pixfmt - > pixelformat = pixelformat ;
pixfmt - > bytesperline = ALIGN ( width , v4l2_format_block_width ( info , 0 ) ) * info - > bpp [ 0 ] ;
pixfmt - > sizeimage = 0 ;
for ( i = 0 ; i < info - > comp_planes ; i + + ) {
unsigned int hdiv = ( i = = 0 ) ? 1 : info - > hdiv ;
unsigned int vdiv = ( i = = 0 ) ? 1 : info - > vdiv ;
unsigned int aligned_width ;
unsigned int aligned_height ;
aligned_width = ALIGN ( width , v4l2_format_block_width ( info , i ) ) ;
aligned_height = ALIGN ( height , v4l2_format_block_height ( info , i ) ) ;
pixfmt - > sizeimage + = info - > bpp [ i ] *
DIV_ROUND_UP ( aligned_width , hdiv ) *
DIV_ROUND_UP ( aligned_height , vdiv ) ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l2_fill_pixfmt ) ;
2020-10-13 17:54:00 +03:00
2020-12-17 20:57:05 +03:00
s64 v4l2_get_link_freq ( struct v4l2_ctrl_handler * handler , unsigned int mul ,
2020-10-13 17:54:00 +03:00
unsigned int div )
{
struct v4l2_ctrl * ctrl ;
s64 freq ;
ctrl = v4l2_ctrl_find ( handler , V4L2_CID_LINK_FREQ ) ;
if ( ctrl ) {
struct v4l2_querymenu qm = { . id = V4L2_CID_LINK_FREQ } ;
int ret ;
qm . index = v4l2_ctrl_g_ctrl ( ctrl ) ;
ret = v4l2_querymenu ( handler , & qm ) ;
if ( ret )
return - ENOENT ;
freq = qm . value ;
} else {
if ( ! mul | | ! div )
return - ENOENT ;
ctrl = v4l2_ctrl_find ( handler , V4L2_CID_PIXEL_RATE ) ;
if ( ! ctrl )
return - ENOENT ;
freq = div_u64 ( v4l2_ctrl_g_ctrl_int64 ( ctrl ) * mul , div ) ;
2021-02-18 20:16:40 +03:00
pr_warn ( " %s: Link frequency estimated using pixel rate: result might be inaccurate \n " ,
__func__ ) ;
pr_warn ( " %s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver \n " ,
__func__ ) ;
2020-10-13 17:54:00 +03:00
}
return freq > 0 ? freq : - EINVAL ;
}
2020-12-17 20:57:05 +03:00
EXPORT_SYMBOL_GPL ( v4l2_get_link_freq ) ;