2008-11-30 03:36:58 +03:00
/*
V4L2 device support .
Copyright ( C ) 2008 Hans Verkuil < hverkuil @ xs4all . nl >
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 .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/types.h>
# include <linux/ioctl.h>
# include <linux/i2c.h>
2010-03-23 17:23:29 +03:00
# if defined(CONFIG_SPI)
# include <linux/spi/spi.h>
# endif
2008-11-30 03:36:58 +03:00
# include <linux/videodev2.h>
# include <media/v4l2-device.h>
2010-05-16 16:24:06 +04:00
# include <media/v4l2-ctrls.h>
2008-11-30 03:36:58 +03:00
int v4l2_device_register ( struct device * dev , struct v4l2_device * v4l2_dev )
{
2009-02-14 17:54:23 +03:00
if ( v4l2_dev = = NULL )
2008-11-30 03:36:58 +03:00
return - EINVAL ;
2009-02-14 17:54:23 +03:00
2008-11-30 03:36:58 +03:00
INIT_LIST_HEAD ( & v4l2_dev - > subdevs ) ;
spin_lock_init ( & v4l2_dev - > lock ) ;
2010-11-26 12:47:28 +03:00
mutex_init ( & v4l2_dev - > ioctl_lock ) ;
2008-11-30 03:36:58 +03:00
v4l2_dev - > dev = dev ;
2009-02-14 17:54:23 +03:00
if ( dev = = NULL ) {
/* If dev == NULL, then name must be filled in by the caller */
WARN_ON ( ! v4l2_dev - > name [ 0 ] ) ;
return 0 ;
}
/* Set name to driver name + device name if it is empty. */
if ( ! v4l2_dev - > name [ 0 ] )
snprintf ( v4l2_dev - > name , sizeof ( v4l2_dev - > name ) , " %s %s " ,
2009-03-25 02:38:22 +03:00
dev - > driver - > name , dev_name ( dev ) ) ;
2009-02-14 17:54:23 +03:00
if ( dev_get_drvdata ( dev ) )
v4l2_warn ( v4l2_dev , " Non-NULL drvdata on register \n " ) ;
2008-11-30 03:36:58 +03:00
dev_set_drvdata ( dev , v4l2_dev ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l2_device_register ) ;
2009-05-02 17:12:50 +04:00
int v4l2_device_set_name ( struct v4l2_device * v4l2_dev , const char * basename ,
atomic_t * instance )
{
int num = atomic_inc_return ( instance ) - 1 ;
int len = strlen ( basename ) ;
if ( basename [ len - 1 ] > = ' 0 ' & & basename [ len - 1 ] < = ' 9 ' )
snprintf ( v4l2_dev - > name , sizeof ( v4l2_dev - > name ) ,
" %s-%d " , basename , num ) ;
else
snprintf ( v4l2_dev - > name , sizeof ( v4l2_dev - > name ) ,
" %s%d " , basename , num ) ;
return num ;
}
EXPORT_SYMBOL_GPL ( v4l2_device_set_name ) ;
2009-03-14 14:28:45 +03:00
void v4l2_device_disconnect ( struct v4l2_device * v4l2_dev )
{
if ( v4l2_dev - > dev ) {
dev_set_drvdata ( v4l2_dev - > dev , NULL ) ;
v4l2_dev - > dev = NULL ;
}
}
EXPORT_SYMBOL_GPL ( v4l2_device_disconnect ) ;
2008-11-30 03:36:58 +03:00
void v4l2_device_unregister ( struct v4l2_device * v4l2_dev )
{
struct v4l2_subdev * sd , * next ;
2009-02-14 17:54:23 +03:00
if ( v4l2_dev = = NULL )
2008-11-30 03:36:58 +03:00
return ;
2009-03-14 14:28:45 +03:00
v4l2_device_disconnect ( v4l2_dev ) ;
2009-02-14 17:54:23 +03:00
/* Unregister subdevs */
2009-05-02 17:58:51 +04:00
list_for_each_entry_safe ( sd , next , & v4l2_dev - > subdevs , list ) {
2008-11-30 03:36:58 +03:00
v4l2_device_unregister_subdev ( sd ) ;
2009-06-10 18:58:22 +04:00
# if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
2009-05-02 17:58:51 +04:00
if ( sd - > flags & V4L2_SUBDEV_FL_IS_I2C ) {
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
/* We need to unregister the i2c client explicitly.
We cannot rely on i2c_del_adapter to always
unregister clients for us , since if the i2c bus
is a platform bus , then it is never deleted . */
if ( client )
i2c_unregister_device ( client ) ;
}
2010-03-23 17:23:29 +03:00
# endif
# if defined(CONFIG_SPI)
if ( sd - > flags & V4L2_SUBDEV_FL_IS_SPI ) {
struct spi_device * spi = v4l2_get_subdevdata ( sd ) ;
if ( spi )
spi_unregister_device ( spi ) ;
}
2009-05-11 20:37:41 +04:00
# endif
2009-05-02 17:58:51 +04:00
}
2008-11-30 03:36:58 +03:00
}
EXPORT_SYMBOL_GPL ( v4l2_device_unregister ) ;
2009-02-14 17:54:23 +03:00
int v4l2_device_register_subdev ( struct v4l2_device * v4l2_dev ,
struct v4l2_subdev * sd )
2008-11-30 03:36:58 +03:00
{
2010-05-16 16:24:06 +04:00
int err ;
2008-11-30 03:36:58 +03:00
/* Check for valid input */
2009-02-14 17:54:23 +03:00
if ( v4l2_dev = = NULL | | sd = = NULL | | ! sd - > name [ 0 ] )
2008-11-30 03:36:58 +03:00
return - EINVAL ;
/* Warn if we apparently re-register a subdev */
2009-02-14 18:00:53 +03:00
WARN_ON ( sd - > v4l2_dev ! = NULL ) ;
2008-11-30 03:36:58 +03:00
if ( ! try_module_get ( sd - > owner ) )
return - ENODEV ;
2011-01-08 13:15:53 +03:00
sd - > v4l2_dev = v4l2_dev ;
if ( sd - > internal_ops & & sd - > internal_ops - > registered ) {
err = sd - > internal_ops - > registered ( sd ) ;
if ( err )
return err ;
}
2010-05-16 16:24:06 +04:00
/* This just returns 0 if either of the two args is NULL */
err = v4l2_ctrl_add_handler ( v4l2_dev - > ctrl_handler , sd - > ctrl_handler ) ;
2011-01-08 13:15:53 +03:00
if ( err ) {
if ( sd - > internal_ops & & sd - > internal_ops - > unregistered )
sd - > internal_ops - > unregistered ( sd ) ;
2010-05-16 16:24:06 +04:00
return err ;
2011-01-08 13:15:53 +03:00
}
2009-02-14 17:54:23 +03:00
spin_lock ( & v4l2_dev - > lock ) ;
list_add_tail ( & sd - > list , & v4l2_dev - > subdevs ) ;
spin_unlock ( & v4l2_dev - > lock ) ;
2008-11-30 03:36:58 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l2_device_register_subdev ) ;
void v4l2_device_unregister_subdev ( struct v4l2_subdev * sd )
{
/* return if it isn't registered */
2009-02-14 18:00:53 +03:00
if ( sd = = NULL | | sd - > v4l2_dev = = NULL )
2008-11-30 03:36:58 +03:00
return ;
2009-02-14 18:00:53 +03:00
spin_lock ( & sd - > v4l2_dev - > lock ) ;
2008-11-30 03:36:58 +03:00
list_del ( & sd - > list ) ;
2009-02-14 18:00:53 +03:00
spin_unlock ( & sd - > v4l2_dev - > lock ) ;
2011-01-08 13:15:53 +03:00
if ( sd - > internal_ops & & sd - > internal_ops - > unregistered )
sd - > internal_ops - > unregistered ( sd ) ;
2009-02-14 18:00:53 +03:00
sd - > v4l2_dev = NULL ;
2008-11-30 03:36:58 +03:00
module_put ( sd - > owner ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_device_unregister_subdev ) ;