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 .
*
* 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 of the License , or ( at your option ) any later version .
*
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 .
*
* 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 of the License , or ( at your option ) any later version .
*
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>
2007-02-24 02:55:14 +03:00
# include <linux/i2c.h>
2010-03-23 17:23:29 +03:00
# if defined(CONFIG_SPI)
# include <linux/spi/spi.h>
# endif
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/pgtable.h>
# 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
MODULE_AUTHOR ( " Bill Dirks, Justin Schoeman, Gerd Knorr " ) ;
MODULE_DESCRIPTION ( " misc helper functions for v4l2 device drivers " ) ;
MODULE_LICENSE ( " GPL " ) ;
/*
*
* 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 ;
2009-01-17 17:26:59 +03:00
strlcpy ( 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-04-01 10:41:09 +04:00
/* I2C Helper functions */
2007-09-12 15:32:50 +04:00
2013-05-26 17:01:42 +04:00
# if IS_ENABLED(CONFIG_I2C)
2008-11-23 18:19:45 +03:00
void v4l2_i2c_subdev_init ( struct v4l2_subdev * sd , struct i2c_client * client ,
const struct v4l2_subdev_ops * ops )
{
v4l2_subdev_init ( sd , ops ) ;
2009-05-02 17:58:51 +04:00
sd - > flags | = V4L2_SUBDEV_FL_IS_I2C ;
2008-11-23 18:19:45 +03:00
/* the owner is the same as the i2c_client's driver owner */
2013-09-29 12:51:01 +04:00
sd - > owner = client - > dev . driver - > owner ;
2013-06-10 22:07:35 +04:00
sd - > dev = & client - > dev ;
2008-11-23 18:19:45 +03:00
/* i2c_client and v4l2_subdev point to one another */
v4l2_set_subdevdata ( sd , client ) ;
i2c_set_clientdata ( client , sd ) ;
/* initialize name */
snprintf ( sd - > name , sizeof ( sd - > name ) , " %s %d-%04x " ,
2013-09-29 12:51:01 +04:00
client - > dev . driver - > name , i2c_adapter_id ( client - > adapter ) ,
2008-11-23 18:19:45 +03:00
client - > addr ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_subdev_init ) ;
2009-06-10 00:12:33 +04:00
/* Load an i2c sub-device. */
struct v4l2_subdev * v4l2_i2c_new_subdev_board ( struct v4l2_device * v4l2_dev ,
2010-09-24 17:16:44 +04:00
struct i2c_adapter * adapter , struct i2c_board_info * info ,
const unsigned short * probe_addrs )
2009-06-10 00:12:33 +04:00
{
struct v4l2_subdev * sd = NULL ;
struct i2c_client * client ;
BUG_ON ( ! v4l2_dev ) ;
2010-09-24 17:16:44 +04:00
request_module ( I2C_MODULE_PREFIX " %s " , info - > type ) ;
2009-06-10 00:12:33 +04:00
/* Create the i2c client */
if ( info - > addr = = 0 & & probe_addrs )
2010-08-11 20:20:56 +04:00
client = i2c_new_probed_device ( adapter , info , probe_addrs ,
NULL ) ;
2009-06-10 00:12:33 +04:00
else
client = i2c_new_device ( adapter , info ) ;
/* Note: by loading the module first we are certain that c->driver
will be set if the driver was found . If the module was not loaded
first , then the i2c core tries to delay - load the module for us ,
and then c - > driver is still NULL until the module is finally
loaded . This delay - load mechanism doesn ' t work if other drivers
want to use the i2c device , so explicitly loading the module
is the best alternative . */
2013-09-29 12:51:01 +04:00
if ( client = = NULL | | client - > dev . driver = = NULL )
2009-06-10 00:12:33 +04:00
goto error ;
/* Lock the module so we can safely get the v4l2_subdev pointer */
2013-09-29 12:51:01 +04:00
if ( ! try_module_get ( client - > dev . driver - > owner ) )
2009-06-10 00:12:33 +04:00
goto error ;
sd = i2c_get_clientdata ( client ) ;
/* Register with the v4l2_device which increases the module's
use count as well . */
if ( v4l2_device_register_subdev ( v4l2_dev , sd ) )
sd = NULL ;
/* Decrease the module use count to match the first try_module_get. */
2013-09-29 12:51:01 +04:00
module_put ( client - > dev . driver - > owner ) ;
2009-06-10 00:12:33 +04:00
error :
/* If we have a client but no subdev, then something went wrong and
we must unregister the client . */
if ( client & & sd = = NULL )
i2c_unregister_device ( client ) ;
return sd ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_new_subdev_board ) ;
2011-01-08 13:08:02 +03:00
struct v4l2_subdev * v4l2_i2c_new_subdev ( struct v4l2_device * v4l2_dev ,
2010-09-24 17:16:44 +04:00
struct i2c_adapter * adapter , const char * client_type ,
2009-06-10 00:12:33 +04:00
u8 addr , const unsigned short * probe_addrs )
{
struct i2c_board_info info ;
/* Setup the i2c board info with the device type and
the device address . */
memset ( & info , 0 , sizeof ( info ) ) ;
strlcpy ( info . type , client_type , sizeof ( info . type ) ) ;
info . addr = addr ;
2010-09-24 17:16:44 +04:00
return v4l2_i2c_new_subdev_board ( v4l2_dev , adapter , & info , probe_addrs ) ;
2009-06-10 00:12:33 +04:00
}
2011-01-08 13:08:02 +03:00
EXPORT_SYMBOL_GPL ( v4l2_i2c_new_subdev ) ;
2009-06-10 00:12:33 +04:00
2009-02-22 00:08:41 +03:00
/* Return i2c client address of v4l2_subdev. */
unsigned short v4l2_i2c_subdev_addr ( struct v4l2_subdev * sd )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
return client ? client - > addr : I2C_CLIENT_END ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_subdev_addr ) ;
2009-01-19 01:37:59 +03:00
/* Return a list of I2C tuner addresses to probe. Use only if the tuner
addresses are unknown . */
const unsigned short * v4l2_i2c_tuner_addrs ( enum v4l2_i2c_tuner_type type )
{
static const unsigned short radio_addrs [ ] = {
2013-01-20 02:41:31 +04:00
# if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761)
2009-01-19 01:37:59 +03:00
0x10 ,
# endif
0x60 ,
I2C_CLIENT_END
} ;
static const unsigned short demod_addrs [ ] = {
0x42 , 0x43 , 0x4a , 0x4b ,
I2C_CLIENT_END
} ;
static const unsigned short tv_addrs [ ] = {
0x42 , 0x43 , 0x4a , 0x4b , /* tda8290 */
2009-05-02 16:42:57 +04:00
0x60 , 0x61 , 0x62 , 0x63 , 0x64 ,
2009-01-19 01:37:59 +03:00
I2C_CLIENT_END
} ;
switch ( type ) {
case ADDRS_RADIO :
return radio_addrs ;
case ADDRS_DEMOD :
return demod_addrs ;
case ADDRS_TV :
return tv_addrs ;
case ADDRS_TV_WITH_DEMOD :
return tv_addrs + 4 ;
}
return NULL ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_tuner_addrs ) ;
2009-06-12 23:31:29 +04:00
# endif /* defined(CONFIG_I2C) */
2010-03-23 17:23:29 +03:00
# if defined(CONFIG_SPI)
2012-07-26 17:48:25 +04:00
/* Load an spi sub-device. */
2010-03-23 17:23:29 +03:00
void v4l2_spi_subdev_init ( struct v4l2_subdev * sd , struct spi_device * spi ,
const struct v4l2_subdev_ops * ops )
{
v4l2_subdev_init ( sd , ops ) ;
sd - > flags | = V4L2_SUBDEV_FL_IS_SPI ;
/* the owner is the same as the spi_device's driver owner */
sd - > owner = spi - > dev . driver - > owner ;
2013-06-10 22:07:35 +04:00
sd - > dev = & spi - > dev ;
2010-03-23 17:23:29 +03:00
/* spi_device and v4l2_subdev point to one another */
v4l2_set_subdevdata ( sd , spi ) ;
spi_set_drvdata ( spi , sd ) ;
/* initialize name */
strlcpy ( sd - > name , spi - > dev . driver - > name , sizeof ( sd - > name ) ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_spi_subdev_init ) ;
struct v4l2_subdev * v4l2_spi_new_subdev ( struct v4l2_device * v4l2_dev ,
struct spi_master * master , struct spi_board_info * info )
{
struct v4l2_subdev * sd = NULL ;
struct spi_device * spi = NULL ;
BUG_ON ( ! v4l2_dev ) ;
2012-09-17 13:51:27 +04:00
if ( info - > modalias [ 0 ] )
2010-03-23 17:23:29 +03:00
request_module ( info - > modalias ) ;
spi = spi_new_device ( master , info ) ;
if ( spi = = NULL | | spi - > dev . driver = = NULL )
goto error ;
if ( ! try_module_get ( spi - > dev . driver - > owner ) )
goto error ;
sd = spi_get_drvdata ( spi ) ;
/* Register with the v4l2_device which increases the module's
use count as well . */
if ( v4l2_device_register_subdev ( v4l2_dev , sd ) )
sd = NULL ;
/* Decrease the module use count to match the first try_module_get. */
module_put ( spi - > dev . driver - > owner ) ;
error :
/* If we have a client but no subdev, then something went wrong and
we must unregister the client . */
2016-07-19 20:54:16 +03:00
if ( ! sd )
2010-03-23 17:23:29 +03:00
spi_unregister_device ( spi ) ;
return sd ;
}
EXPORT_SYMBOL_GPL ( v4l2_spi_new_subdev ) ;
# endif /* defined(CONFIG_SPI) */
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 ;
}
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 ) ;
2012-09-15 14:51:47 +04:00
void v4l2_get_timestamp ( struct timeval * tv )
{
struct timespec ts ;
ktime_get_ts ( & ts ) ;
tv - > tv_sec = ts . tv_sec ;
tv - > tv_usec = ts . tv_nsec / NSEC_PER_USEC ;
}
EXPORT_SYMBOL_GPL ( v4l2_get_timestamp ) ;
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 ) ;