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
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# 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>
2007-04-27 19:31:08 +04:00
# include <media/v4l2-chip-ident.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 */
/* Check for correctness of the ctrl's value based on the data from
struct v4l2_queryctrl and the available menu items . Note that
menu_items may be NULL , in that case it is ignored . */
int v4l2_ctrl_check ( struct v4l2_ext_control * ctrl , struct v4l2_queryctrl * qctrl ,
2010-12-29 20:25:52 +03:00
const char * const * menu_items )
2006-06-18 21:11:08 +04:00
{
if ( qctrl - > flags & V4L2_CTRL_FLAG_DISABLED )
return - EINVAL ;
if ( qctrl - > flags & V4L2_CTRL_FLAG_GRABBED )
return - EBUSY ;
2009-08-12 01:47:18 +04:00
if ( qctrl - > type = = V4L2_CTRL_TYPE_STRING )
return 0 ;
2006-06-18 21:11:08 +04:00
if ( qctrl - > type = = V4L2_CTRL_TYPE_BUTTON | |
qctrl - > type = = V4L2_CTRL_TYPE_INTEGER64 | |
qctrl - > type = = V4L2_CTRL_TYPE_CTRL_CLASS )
return 0 ;
if ( ctrl - > value < qctrl - > minimum | | ctrl - > value > qctrl - > maximum )
return - ERANGE ;
if ( qctrl - > type = = V4L2_CTRL_TYPE_MENU & & menu_items ! = NULL ) {
if ( menu_items [ ctrl - > value ] = = NULL | |
menu_items [ ctrl - > value ] [ 0 ] = = ' \0 ' )
return - EINVAL ;
}
2011-05-23 11:07:05 +04:00
if ( qctrl - > type = = V4L2_CTRL_TYPE_BITMASK & &
( ctrl - > value & ~ qctrl - > maximum ) )
return - ERANGE ;
2006-06-18 21:11:08 +04:00
return 0 ;
}
2008-02-02 17:25:31 +03:00
EXPORT_SYMBOL ( v4l2_ctrl_check ) ;
2006-06-18 21:11:08 +04:00
2008-08-08 14:55:00 +04:00
/* Fill in a struct v4l2_queryctrl */
int v4l2_ctrl_query_fill ( struct v4l2_queryctrl * qctrl , s32 min , s32 max , s32 step , s32 def )
{
2010-08-01 21:32:42 +04:00
const char * name ;
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
/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
2008-08-08 19:43:59 +04:00
the menu . The qctrl pointer may be NULL , in which case it is ignored .
If menu_items is NULL , then the menu items are retrieved using
v4l2_ctrl_get_menu . */
2006-06-18 21:11:08 +04:00
int v4l2_ctrl_query_menu ( struct v4l2_querymenu * qmenu , struct v4l2_queryctrl * qctrl ,
2010-12-29 20:25:52 +03:00
const char * const * menu_items )
2006-06-18 21:11:08 +04:00
{
int i ;
2008-08-08 15:34:19 +04:00
qmenu - > reserved = 0 ;
2008-08-08 19:43:59 +04:00
if ( menu_items = = NULL )
menu_items = v4l2_ctrl_get_menu ( qmenu - > id ) ;
2006-06-18 21:11:08 +04:00
if ( menu_items = = NULL | |
( qctrl & & ( qmenu - > index < qctrl - > minimum | | qmenu - > index > qctrl - > maximum ) ) )
return - EINVAL ;
for ( i = 0 ; i < qmenu - > index & & menu_items [ i ] ; i + + ) ;
if ( menu_items [ i ] = = NULL | | menu_items [ i ] [ 0 ] = = ' \0 ' )
return - EINVAL ;
2009-01-17 17:26:59 +03:00
strlcpy ( qmenu - > name , menu_items [ qmenu - > index ] , sizeof ( qmenu - > name ) ) ;
2006-06-18 21:11:08 +04:00
return 0 ;
}
2008-02-02 17:25:31 +03:00
EXPORT_SYMBOL ( v4l2_ctrl_query_menu ) ;
2006-06-18 21:11:08 +04:00
2008-08-08 15:34:19 +04:00
/* Fill in a struct v4l2_querymenu based on the specified array of valid
menu items ( terminated by V4L2_CTRL_MENU_IDS_END ) .
Use this if there are ' holes ' in the list of valid menu items . */
int v4l2_ctrl_query_menu_valid_items ( struct v4l2_querymenu * qmenu , const u32 * ids )
{
2010-12-29 20:25:52 +03:00
const char * const * menu_items = v4l2_ctrl_get_menu ( qmenu - > id ) ;
2008-08-08 15:34:19 +04:00
qmenu - > reserved = 0 ;
if ( menu_items = = NULL | | ids = = NULL )
return - EINVAL ;
while ( * ids ! = V4L2_CTRL_MENU_IDS_END ) {
if ( * ids + + = = qmenu - > index ) {
2009-01-17 17:26:59 +03:00
strlcpy ( qmenu - > name , menu_items [ qmenu - > index ] ,
sizeof ( qmenu - > name ) ) ;
2008-08-08 15:34:19 +04:00
return 0 ;
}
}
return - EINVAL ;
}
EXPORT_SYMBOL ( v4l2_ctrl_query_menu_valid_items ) ;
2006-06-18 21:11:08 +04:00
/* ctrl_classes points to an array of u32 pointers, the last element is
a NULL pointer . Each u32 array is a 0 - terminated array of control IDs .
Each array must be sorted low to high and belong to the same control
2009-02-13 16:57:48 +03:00
class . The array of u32 pointers must also be sorted , from low class IDs
2006-06-18 21:11:08 +04:00
to high class IDs .
This function returns the first ID that follows after the given ID .
When no more controls are available 0 is returned . */
u32 v4l2_ctrl_next ( const u32 * const * ctrl_classes , u32 id )
{
2007-07-19 11:53:36 +04:00
u32 ctrl_class = V4L2_CTRL_ID2CLASS ( id ) ;
2006-06-18 21:11:08 +04:00
const u32 * pctrl ;
if ( ctrl_classes = = NULL )
return 0 ;
2007-07-19 11:53:36 +04:00
/* if no query is desired, then check if the ID is part of ctrl_classes */
if ( ( id & V4L2_CTRL_FLAG_NEXT_CTRL ) = = 0 ) {
/* find class */
while ( * ctrl_classes & & V4L2_CTRL_ID2CLASS ( * * ctrl_classes ) ! = ctrl_class )
ctrl_classes + + ;
if ( * ctrl_classes = = NULL )
return 0 ;
pctrl = * ctrl_classes ;
/* find control ID */
while ( * pctrl & & * pctrl ! = id ) pctrl + + ;
return * pctrl ? id : 0 ;
}
2006-06-18 21:11:08 +04:00
id & = V4L2_CTRL_ID_MASK ;
id + + ; /* select next control */
/* find first class that matches (or is greater than) the class of
the ID */
while ( * ctrl_classes & & V4L2_CTRL_ID2CLASS ( * * ctrl_classes ) < ctrl_class )
ctrl_classes + + ;
/* no more classes */
if ( * ctrl_classes = = NULL )
return 0 ;
pctrl = * ctrl_classes ;
/* find first ctrl within the class that is >= ID */
while ( * pctrl & & * pctrl < id ) pctrl + + ;
if ( * pctrl )
return * pctrl ;
/* we are at the end of the controls of the current class. */
/* continue with next class if available */
ctrl_classes + + ;
if ( * ctrl_classes = = NULL )
return 0 ;
return * * ctrl_classes ;
}
2008-02-02 17:25:31 +03:00
EXPORT_SYMBOL ( v4l2_ctrl_next ) ;
2006-06-18 21:11:08 +04:00
2008-12-30 13:14:19 +03:00
int v4l2_chip_match_host ( const struct v4l2_dbg_match * match )
2008-01-30 00:32:35 +03:00
{
2008-12-30 13:14:19 +03:00
switch ( match - > type ) {
2008-01-30 00:32:35 +03:00
case V4L2_CHIP_MATCH_HOST :
2008-12-30 13:14:19 +03:00
return match - > addr = = 0 ;
2008-01-30 00:32:35 +03:00
default :
return 0 ;
}
}
EXPORT_SYMBOL ( v4l2_chip_match_host ) ;
# if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
2008-12-30 13:14:19 +03:00
int v4l2_chip_match_i2c_client ( struct i2c_client * c , const struct v4l2_dbg_match * match )
2007-02-24 02:55:14 +03:00
{
2008-12-30 13:14:19 +03:00
int len ;
if ( c = = NULL | | match = = NULL )
return 0 ;
switch ( match - > type ) {
2007-02-24 02:55:14 +03:00
case V4L2_CHIP_MATCH_I2C_DRIVER :
2008-12-30 13:14:19 +03:00
if ( c - > driver = = NULL | | c - > driver - > driver . name = = NULL )
return 0 ;
len = strlen ( c - > driver - > driver . name ) ;
/* legacy drivers have a ' suffix, don't try to match that */
if ( len & & c - > driver - > driver . name [ len - 1 ] = = ' \' ' )
len - - ;
return len & & ! strncmp ( c - > driver - > driver . name , match - > name , len ) ;
2007-02-24 02:55:14 +03:00
case V4L2_CHIP_MATCH_I2C_ADDR :
2008-12-30 13:14:19 +03:00
return c - > addr = = match - > addr ;
2007-02-24 02:55:14 +03:00
default :
return 0 ;
}
}
2008-01-30 00:32:35 +03:00
EXPORT_SYMBOL ( v4l2_chip_match_i2c_client ) ;
2007-02-24 02:55:14 +03:00
2008-12-30 13:14:19 +03:00
int v4l2_chip_ident_i2c_client ( struct i2c_client * c , struct v4l2_dbg_chip_ident * chip ,
2007-04-27 19:31:08 +04:00
u32 ident , u32 revision )
{
2008-12-30 13:14:19 +03:00
if ( ! v4l2_chip_match_i2c_client ( c , & chip - > match ) )
2007-04-27 19:31:08 +04:00
return 0 ;
if ( chip - > ident = = V4L2_IDENT_NONE ) {
chip - > ident = ident ;
chip - > revision = revision ;
}
else {
chip - > ident = V4L2_IDENT_AMBIGUOUS ;
chip - > revision = 0 ;
}
return 0 ;
}
2008-01-30 00:32:35 +03:00
EXPORT_SYMBOL ( v4l2_chip_ident_i2c_client ) ;
2007-02-24 02:55:14 +03:00
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
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 */
sd - > owner = client - > driver - > driver . owner ;
/* 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 " ,
client - > driver - > driver . name , i2c_adapter_id ( client - > adapter ) ,
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 . */
if ( client = = NULL | | client - > driver = = NULL )
goto error ;
/* Lock the module so we can safely get the v4l2_subdev pointer */
if ( ! try_module_get ( client - > driver - > driver . owner ) )
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. */
module_put ( client - > driver - > driver . owner ) ;
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 [ ] = {
# if defined(CONFIG_MEDIA_TUNER_TEA5761) || defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE)
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 ;
/* 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 ) ;
if ( info - > modalias )
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 . */
if ( spi & & sd = = NULL )
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 ) ;
/* Round to nearest aligned value */
if ( align )
x = ( x + ( 1 < < ( align - 1 ) ) ) & mask ;
/* Clamp to aligned value of min and max */
if ( x < min )
x = ( min + ~ mask ) & mask ;
else if ( x > max )
x = max & mask ;
return x ;
}
/* Bound an image to have a width between wmin and wmax, and height between
* hmin and hmax , inclusive . Additionally , the width will be a multiple of
* 2 ^ walign , the height will be a multiple of 2 ^ halign , and the overall size
* ( width * height ) will be a multiple of 2 ^ salign . The image may be shrunk
* or enlarged to fit the alignment constraints .
*
* The width or height maximum must not be smaller than the corresponding
* minimum . The alignments must not be so high there are no possible image
* sizes within the allowed bounds . wmin and hmin must be at least 1
* ( don ' t use 0 ) . If you don ' t care about a certain alignment , specify 0 ,
* as 2 ^ 0 is 1 and one byte alignment is equivalent to no alignment . If
* you only want to adjust downward , specify a maximum that ' s the same as
* the initial value .
*/
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
/**
* v4l_fill_dv_preset_info - fill description of a digital video preset
* @ preset - preset value
* @ info - pointer to struct v4l2_dv_enum_preset
*
* drivers can use this helper function to fill description of dv preset
* in info .
*/
int v4l_fill_dv_preset_info ( u32 preset , struct v4l2_dv_enum_preset * info )
{
static const struct v4l2_dv_preset_info {
u16 width ;
u16 height ;
const char * name ;
} dv_presets [ ] = {
{ 0 , 0 , " Invalid " } , /* V4L2_DV_INVALID */
{ 720 , 480 , " 480p@59.94 " } , /* V4L2_DV_480P59_94 */
{ 720 , 576 , " 576p@50 " } , /* V4L2_DV_576P50 */
{ 1280 , 720 , " 720p@24 " } , /* V4L2_DV_720P24 */
{ 1280 , 720 , " 720p@25 " } , /* V4L2_DV_720P25 */
{ 1280 , 720 , " 720p@30 " } , /* V4L2_DV_720P30 */
{ 1280 , 720 , " 720p@50 " } , /* V4L2_DV_720P50 */
{ 1280 , 720 , " 720p@59.94 " } , /* V4L2_DV_720P59_94 */
{ 1280 , 720 , " 720p@60 " } , /* V4L2_DV_720P60 */
{ 1920 , 1080 , " 1080i@29.97 " } , /* V4L2_DV_1080I29_97 */
{ 1920 , 1080 , " 1080i@30 " } , /* V4L2_DV_1080I30 */
{ 1920 , 1080 , " 1080i@25 " } , /* V4L2_DV_1080I25 */
{ 1920 , 1080 , " 1080i@50 " } , /* V4L2_DV_1080I50 */
{ 1920 , 1080 , " 1080i@60 " } , /* V4L2_DV_1080I60 */
{ 1920 , 1080 , " 1080p@24 " } , /* V4L2_DV_1080P24 */
{ 1920 , 1080 , " 1080p@25 " } , /* V4L2_DV_1080P25 */
{ 1920 , 1080 , " 1080p@30 " } , /* V4L2_DV_1080P30 */
{ 1920 , 1080 , " 1080p@50 " } , /* V4L2_DV_1080P50 */
{ 1920 , 1080 , " 1080p@60 " } , /* V4L2_DV_1080P60 */
} ;
if ( info = = NULL | | preset > = ARRAY_SIZE ( dv_presets ) )
return - EINVAL ;
info - > preset = preset ;
info - > width = dv_presets [ preset ] . width ;
info - > height = dv_presets [ preset ] . height ;
strlcpy ( info - > name , dv_presets [ preset ] . name , sizeof ( info - > name ) ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l_fill_dv_preset_info ) ;
2010-08-27 20:41:44 +04:00
2012-08-10 13:09:26 +04:00
/**
* v4l_match_dv_timings - check if two timings match
* @ t1 - compare this v4l2_dv_timings struct . . .
* @ t2 - with this struct .
* @ pclock_delta - the allowed pixelclock deviation .
*
* Compare t1 with t2 with a given margin of error for the pixelclock .
*/
bool v4l_match_dv_timings ( const struct v4l2_dv_timings * t1 ,
const struct v4l2_dv_timings * t2 ,
unsigned pclock_delta )
{
if ( t1 - > type ! = t2 - > type | | t1 - > type ! = V4L2_DV_BT_656_1120 )
return false ;
if ( t1 - > bt . width = = t2 - > bt . width & &
t1 - > bt . height = = t2 - > bt . height & &
t1 - > bt . interlaced = = t2 - > bt . interlaced & &
t1 - > bt . polarities = = t2 - > bt . polarities & &
t1 - > bt . pixelclock > = t2 - > bt . pixelclock - pclock_delta & &
t1 - > bt . pixelclock < = t2 - > bt . pixelclock + pclock_delta & &
t1 - > bt . hfrontporch = = t2 - > bt . hfrontporch & &
t1 - > bt . vfrontporch = = t2 - > bt . vfrontporch & &
t1 - > bt . vsync = = t2 - > bt . vsync & &
t1 - > bt . vbackporch = = t2 - > bt . vbackporch & &
( ! t1 - > bt . interlaced | |
( t1 - > bt . il_vfrontporch = = t2 - > bt . il_vfrontporch & &
t1 - > bt . il_vsync = = t2 - > bt . il_vsync & &
t1 - > bt . il_vbackporch = = t2 - > bt . il_vbackporch ) ) )
return true ;
return false ;
}
EXPORT_SYMBOL_GPL ( v4l_match_dv_timings ) ;
2012-08-10 13:11:12 +04:00
/*
* CVT defines
* Based on Coordinated Video Timings Standard
* version 1.1 September 10 , 2003
*/
# define CVT_PXL_CLK_GRAN 250000 /* pixel clock granularity */
/* Normal blanking */
# define CVT_MIN_V_BPORCH 7 /* lines */
# define CVT_MIN_V_PORCH_RND 3 /* lines */
# define CVT_MIN_VSYNC_BP 550 /* min time of vsync + back porch (us) */
/* Normal blanking for CVT uses GTF to calculate horizontal blanking */
# define CVT_CELL_GRAN 8 /* character cell granularity */
# define CVT_M 600 /* blanking formula gradient */
# define CVT_C 40 /* blanking formula offset */
# define CVT_K 128 /* blanking formula scaling factor */
# define CVT_J 20 /* blanking formula scaling factor */
# define CVT_C_PRIME (((CVT_C - CVT_J) * CVT_K / 256) + CVT_J)
# define CVT_M_PRIME (CVT_K * CVT_M / 256)
/* Reduced Blanking */
# define CVT_RB_MIN_V_BPORCH 7 /* lines */
# define CVT_RB_V_FPORCH 3 /* lines */
# define CVT_RB_MIN_V_BLANK 460 /* us */
# define CVT_RB_H_SYNC 32 /* pixels */
# define CVT_RB_H_BPORCH 80 /* pixels */
# define CVT_RB_H_BLANK 160 /* pixels */
/** v4l2_detect_cvt - detect if the given timings follow the CVT standard
* @ frame_height - the total height of the frame ( including blanking ) in lines .
* @ hfreq - the horizontal frequency in Hz .
* @ vsync - the height of the vertical sync in lines .
* @ polarities - the horizontal and vertical polarities ( same as struct
* v4l2_bt_timings polarities ) .
* @ fmt - the resulting timings .
*
* This function will attempt to detect if the given values correspond to a
* valid CVT format . If so , then it will return true , and fmt will be filled
* in with the found CVT timings .
*/
bool v4l2_detect_cvt ( unsigned frame_height , unsigned hfreq , unsigned vsync ,
u32 polarities , struct v4l2_dv_timings * fmt )
{
int v_fp , v_bp , h_fp , h_bp , hsync ;
int frame_width , image_height , image_width ;
bool reduced_blanking ;
unsigned pix_clk ;
if ( vsync < 4 | | vsync > 7 )
return false ;
if ( polarities = = V4L2_DV_VSYNC_POS_POL )
reduced_blanking = false ;
else if ( polarities = = V4L2_DV_HSYNC_POS_POL )
reduced_blanking = true ;
else
return false ;
/* Vertical */
if ( reduced_blanking ) {
v_fp = CVT_RB_V_FPORCH ;
v_bp = ( CVT_RB_MIN_V_BLANK * hfreq + 999999 ) / 1000000 ;
v_bp - = vsync + v_fp ;
if ( v_bp < CVT_RB_MIN_V_BPORCH )
v_bp = CVT_RB_MIN_V_BPORCH ;
} else {
v_fp = CVT_MIN_V_PORCH_RND ;
v_bp = ( CVT_MIN_VSYNC_BP * hfreq + 999999 ) / 1000000 - vsync ;
if ( v_bp < CVT_MIN_V_BPORCH )
v_bp = CVT_MIN_V_BPORCH ;
}
image_height = ( frame_height - v_fp - vsync - v_bp + 1 ) & ~ 0x1 ;
/* Aspect ratio based on vsync */
switch ( vsync ) {
case 4 :
image_width = ( image_height * 4 ) / 3 ;
break ;
case 5 :
image_width = ( image_height * 16 ) / 9 ;
break ;
case 6 :
image_width = ( image_height * 16 ) / 10 ;
break ;
case 7 :
/* special case */
if ( image_height = = 1024 )
image_width = ( image_height * 5 ) / 4 ;
else if ( image_height = = 768 )
image_width = ( image_height * 15 ) / 9 ;
else
return false ;
break ;
default :
return false ;
}
image_width = image_width & ~ 7 ;
/* Horizontal */
if ( reduced_blanking ) {
pix_clk = ( image_width + CVT_RB_H_BLANK ) * hfreq ;
pix_clk = ( pix_clk / CVT_PXL_CLK_GRAN ) * CVT_PXL_CLK_GRAN ;
h_bp = CVT_RB_H_BPORCH ;
hsync = CVT_RB_H_SYNC ;
h_fp = CVT_RB_H_BLANK - h_bp - hsync ;
frame_width = image_width + CVT_RB_H_BLANK ;
} else {
int h_blank ;
unsigned ideal_duty_cycle = CVT_C_PRIME - ( CVT_M_PRIME * 1000 ) / hfreq ;
h_blank = ( image_width * ideal_duty_cycle + ( 100 - ideal_duty_cycle ) / 2 ) /
( 100 - ideal_duty_cycle ) ;
h_blank = h_blank - h_blank % ( 2 * CVT_CELL_GRAN ) ;
if ( h_blank * 100 / image_width < 20 ) {
h_blank = image_width / 5 ;
h_blank = ( h_blank + 0x7 ) & ~ 0x7 ;
}
pix_clk = ( image_width + h_blank ) * hfreq ;
pix_clk = ( pix_clk / CVT_PXL_CLK_GRAN ) * CVT_PXL_CLK_GRAN ;
h_bp = h_blank / 2 ;
frame_width = image_width + h_blank ;
hsync = ( frame_width * 8 + 50 ) / 100 ;
hsync = hsync - hsync % CVT_CELL_GRAN ;
h_fp = h_blank - hsync - h_bp ;
}
fmt - > bt . polarities = polarities ;
fmt - > bt . width = image_width ;
fmt - > bt . height = image_height ;
fmt - > bt . hfrontporch = h_fp ;
fmt - > bt . vfrontporch = v_fp ;
fmt - > bt . hsync = hsync ;
fmt - > bt . vsync = vsync ;
fmt - > bt . hbackporch = frame_width - image_width - h_fp - hsync ;
fmt - > bt . vbackporch = frame_height - image_height - v_fp - vsync ;
fmt - > bt . pixelclock = pix_clk ;
fmt - > bt . standards = V4L2_DV_BT_STD_CVT ;
if ( reduced_blanking )
fmt - > bt . flags | = V4L2_DV_FL_REDUCED_BLANKING ;
return true ;
}
EXPORT_SYMBOL_GPL ( v4l2_detect_cvt ) ;
/*
* GTF defines
* Based on Generalized Timing Formula Standard
* Version 1.1 September 2 , 1999
*/
# define GTF_PXL_CLK_GRAN 250000 /* pixel clock granularity */
# define GTF_MIN_VSYNC_BP 550 /* min time of vsync + back porch (us) */
# define GTF_V_FP 1 /* vertical front porch (lines) */
# define GTF_CELL_GRAN 8 /* character cell granularity */
/* Default */
# define GTF_D_M 600 /* blanking formula gradient */
# define GTF_D_C 40 /* blanking formula offset */
# define GTF_D_K 128 /* blanking formula scaling factor */
# define GTF_D_J 20 /* blanking formula scaling factor */
# define GTF_D_C_PRIME ((((GTF_D_C - GTF_D_J) * GTF_D_K) / 256) + GTF_D_J)
# define GTF_D_M_PRIME ((GTF_D_K * GTF_D_M) / 256)
/* Secondary */
# define GTF_S_M 3600 /* blanking formula gradient */
# define GTF_S_C 40 /* blanking formula offset */
# define GTF_S_K 128 /* blanking formula scaling factor */
# define GTF_S_J 35 /* blanking formula scaling factor */
# define GTF_S_C_PRIME ((((GTF_S_C - GTF_S_J) * GTF_S_K) / 256) + GTF_S_J)
# define GTF_S_M_PRIME ((GTF_S_K * GTF_S_M) / 256)
/** v4l2_detect_gtf - detect if the given timings follow the GTF standard
* @ frame_height - the total height of the frame ( including blanking ) in lines .
* @ hfreq - the horizontal frequency in Hz .
* @ vsync - the height of the vertical sync in lines .
* @ polarities - the horizontal and vertical polarities ( same as struct
* v4l2_bt_timings polarities ) .
* @ aspect - preferred aspect ratio . GTF has no method of determining the
* aspect ratio in order to derive the image width from the
* image height , so it has to be passed explicitly . Usually
* the native screen aspect ratio is used for this . If it
* is not filled in correctly , then 16 : 9 will be assumed .
* @ fmt - the resulting timings .
*
* This function will attempt to detect if the given values correspond to a
* valid GTF format . If so , then it will return true , and fmt will be filled
* in with the found GTF timings .
*/
bool v4l2_detect_gtf ( unsigned frame_height ,
unsigned hfreq ,
unsigned vsync ,
u32 polarities ,
struct v4l2_fract aspect ,
struct v4l2_dv_timings * fmt )
{
int pix_clk ;
int v_fp , v_bp , h_fp , h_bp , hsync ;
int frame_width , image_height , image_width ;
bool default_gtf ;
int h_blank ;
if ( vsync ! = 3 )
return false ;
if ( polarities = = V4L2_DV_VSYNC_POS_POL )
default_gtf = true ;
else if ( polarities = = V4L2_DV_HSYNC_POS_POL )
default_gtf = false ;
else
return false ;
/* Vertical */
v_fp = GTF_V_FP ;
v_bp = ( GTF_MIN_VSYNC_BP * hfreq + 999999 ) / 1000000 - vsync ;
image_height = ( frame_height - v_fp - vsync - v_bp + 1 ) & ~ 0x1 ;
if ( aspect . numerator = = 0 | | aspect . denominator = = 0 ) {
aspect . numerator = 16 ;
aspect . denominator = 9 ;
}
image_width = ( ( image_height * aspect . numerator ) / aspect . denominator ) ;
/* Horizontal */
if ( default_gtf )
h_blank = ( ( image_width * GTF_D_C_PRIME * hfreq ) -
( image_width * GTF_D_M_PRIME * 1000 ) +
( hfreq * ( 100 - GTF_D_C_PRIME ) + GTF_D_M_PRIME * 1000 ) / 2 ) /
( hfreq * ( 100 - GTF_D_C_PRIME ) + GTF_D_M_PRIME * 1000 ) ;
else
h_blank = ( ( image_width * GTF_S_C_PRIME * hfreq ) -
( image_width * GTF_S_M_PRIME * 1000 ) +
( hfreq * ( 100 - GTF_S_C_PRIME ) + GTF_S_M_PRIME * 1000 ) / 2 ) /
( hfreq * ( 100 - GTF_S_C_PRIME ) + GTF_S_M_PRIME * 1000 ) ;
h_blank = h_blank - h_blank % ( 2 * GTF_CELL_GRAN ) ;
frame_width = image_width + h_blank ;
pix_clk = ( image_width + h_blank ) * hfreq ;
pix_clk = pix_clk / GTF_PXL_CLK_GRAN * GTF_PXL_CLK_GRAN ;
hsync = ( frame_width * 8 + 50 ) / 100 ;
hsync = hsync - hsync % GTF_CELL_GRAN ;
h_fp = h_blank / 2 - hsync ;
h_bp = h_blank / 2 ;
fmt - > bt . polarities = polarities ;
fmt - > bt . width = image_width ;
fmt - > bt . height = image_height ;
fmt - > bt . hfrontporch = h_fp ;
fmt - > bt . vfrontporch = v_fp ;
fmt - > bt . hsync = hsync ;
fmt - > bt . vsync = vsync ;
fmt - > bt . hbackporch = frame_width - image_width - h_fp - hsync ;
fmt - > bt . vbackporch = frame_height - image_height - v_fp - vsync ;
fmt - > bt . pixelclock = pix_clk ;
fmt - > bt . standards = V4L2_DV_BT_STD_GTF ;
if ( ! default_gtf )
fmt - > bt . flags | = V4L2_DV_FL_REDUCED_BLANKING ;
return true ;
}
EXPORT_SYMBOL_GPL ( v4l2_detect_gtf ) ;
/** v4l2_calc_aspect_ratio - calculate the aspect ratio based on bytes
* 0x15 and 0x16 from the EDID .
* @ hor_landscape - byte 0x15 from the EDID .
* @ vert_portrait - byte 0x16 from the EDID .
*
* Determines the aspect ratio from the EDID .
* See VESA Enhanced EDID standard , release A , rev 2 , section 3.6 .2 :
* " Horizontal and Vertical Screen Size or Aspect Ratio "
*/
struct v4l2_fract v4l2_calc_aspect_ratio ( u8 hor_landscape , u8 vert_portrait )
{
struct v4l2_fract aspect = { 16 , 9 } ;
u32 tmp ;
u8 ratio ;
/* Nothing filled in, fallback to 16:9 */
if ( ! hor_landscape & & ! vert_portrait )
return aspect ;
/* Both filled in, so they are interpreted as the screen size in cm */
if ( hor_landscape & & vert_portrait ) {
aspect . numerator = hor_landscape ;
aspect . denominator = vert_portrait ;
return aspect ;
}
/* Only one is filled in, so interpret them as a ratio:
( val + 99 ) / 100 */
ratio = hor_landscape | vert_portrait ;
/* Change some rounded values into the exact aspect ratio */
if ( ratio = = 79 ) {
aspect . numerator = 16 ;
aspect . denominator = 9 ;
} else if ( ratio = = 34 ) {
aspect . numerator = 4 ;
aspect . numerator = 3 ;
} else if ( ratio = = 68 ) {
aspect . numerator = 15 ;
aspect . numerator = 9 ;
} else {
aspect . numerator = hor_landscape + 99 ;
aspect . denominator = 100 ;
}
if ( hor_landscape )
return aspect ;
/* The aspect ratio is for portrait, so swap numerator and denominator */
tmp = aspect . denominator ;
aspect . denominator = aspect . numerator ;
aspect . numerator = tmp ;
return aspect ;
}
EXPORT_SYMBOL_GPL ( v4l2_calc_aspect_ratio ) ;
2010-09-30 16:29:37 +04:00
const struct v4l2_frmsize_discrete * v4l2_find_nearest_format (
const struct v4l2_discrete_probe * probe ,
s32 width , s32 height )
2010-08-27 20:41:44 +04:00
{
int i ;
u32 error , min_error = UINT_MAX ;
2010-09-30 16:29:37 +04:00
const struct v4l2_frmsize_discrete * size , * best = NULL ;
2010-08-27 20:41:44 +04:00
if ( ! probe )
return best ;
for ( i = 0 , size = probe - > sizes ; i < probe - > num_sizes ; i + + , size + + ) {
error = abs ( size - > width - width ) + abs ( size - > height - height ) ;
if ( error < min_error ) {
min_error = error ;
best = size ;
}
if ( ! error )
break ;
}
return best ;
}
EXPORT_SYMBOL_GPL ( v4l2_find_nearest_format ) ;