2007-07-19 00:59:15 +04:00
/*
* drivers / media / video / v4l2 - int - device . c
*
* V4L2 internal ioctl interface .
*
* Copyright ( C ) 2007 Nokia Corporation .
*
* Contact : Sakari Ailus < sakari . ailus @ nokia . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*
* 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 . , 51 Franklin St , Fifth Floor , Boston , MA
* 02110 - 1301 USA
*/
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/sort.h>
# include <linux/string.h>
2011-07-03 22:03:12 +04:00
# include <linux/module.h>
2007-07-19 00:59:15 +04:00
# include <media/v4l2-int-device.h>
static DEFINE_MUTEX ( mutex ) ;
static LIST_HEAD ( int_list ) ;
2008-10-18 19:28:36 +04:00
void v4l2_int_device_try_attach_all ( void )
2007-07-19 00:59:15 +04:00
{
2007-10-10 12:37:43 +04:00
struct v4l2_int_device * m , * s ;
2007-07-19 00:59:15 +04:00
2007-10-10 12:37:43 +04:00
list_for_each_entry ( m , & int_list , head ) {
2007-07-19 00:59:15 +04:00
if ( m - > type ! = v4l2_int_type_master )
continue ;
2007-10-10 12:37:43 +04:00
list_for_each_entry ( s , & int_list , head ) {
2007-07-19 00:59:15 +04:00
if ( s - > type ! = v4l2_int_type_slave )
continue ;
/* Slave is connected? */
if ( s - > u . slave - > master )
continue ;
/* Slave wants to attach to master? */
if ( s - > u . slave - > attach_to [ 0 ] ! = 0
& & strncmp ( m - > name , s - > u . slave - > attach_to ,
V4L2NAMESIZE ) )
continue ;
if ( ! try_module_get ( m - > module ) )
continue ;
2007-10-30 11:52:52 +03:00
s - > u . slave - > master = m ;
if ( m - > u . master - > attach ( s ) ) {
s - > u . slave - > master = NULL ;
2007-07-19 00:59:15 +04:00
module_put ( m - > module ) ;
continue ;
}
}
}
}
2008-10-18 19:28:36 +04:00
EXPORT_SYMBOL_GPL ( v4l2_int_device_try_attach_all ) ;
2007-07-19 00:59:15 +04:00
static int ioctl_sort_cmp ( const void * a , const void * b )
{
const struct v4l2_int_ioctl_desc * d1 = a , * d2 = b ;
if ( d1 - > num > d2 - > num )
return 1 ;
if ( d1 - > num < d2 - > num )
return - 1 ;
return 0 ;
}
int v4l2_int_device_register ( struct v4l2_int_device * d )
{
if ( d - > type = = v4l2_int_type_slave )
sort ( d - > u . slave - > ioctls , d - > u . slave - > num_ioctls ,
sizeof ( struct v4l2_int_ioctl_desc ) ,
& ioctl_sort_cmp , NULL ) ;
mutex_lock ( & mutex ) ;
list_add ( & d - > head , & int_list ) ;
v4l2_int_device_try_attach_all ( ) ;
mutex_unlock ( & mutex ) ;
return 0 ;
}
2007-07-30 18:43:55 +04:00
EXPORT_SYMBOL_GPL ( v4l2_int_device_register ) ;
2007-07-19 00:59:15 +04:00
void v4l2_int_device_unregister ( struct v4l2_int_device * d )
{
mutex_lock ( & mutex ) ;
list_del ( & d - > head ) ;
if ( d - > type = = v4l2_int_type_slave
& & d - > u . slave - > master ! = NULL ) {
d - > u . slave - > master - > u . master - > detach ( d ) ;
module_put ( d - > u . slave - > master - > module ) ;
d - > u . slave - > master = NULL ;
}
mutex_unlock ( & mutex ) ;
}
2007-07-30 18:43:55 +04:00
EXPORT_SYMBOL_GPL ( v4l2_int_device_unregister ) ;
2007-07-19 00:59:15 +04:00
/* Adapted from search_extable in extable.c. */
2007-07-20 20:12:51 +04:00
static v4l2_int_ioctl_func * find_ioctl ( struct v4l2_int_slave * slave , int cmd ,
v4l2_int_ioctl_func * no_such_ioctl )
2007-07-19 00:59:15 +04:00
{
const struct v4l2_int_ioctl_desc * first = slave - > ioctls ;
const struct v4l2_int_ioctl_desc * last =
first + slave - > num_ioctls - 1 ;
while ( first < = last ) {
const struct v4l2_int_ioctl_desc * mid ;
mid = ( last - first ) / 2 + first ;
if ( mid - > num < cmd )
first = mid + 1 ;
else if ( mid - > num > cmd )
last = mid - 1 ;
else
return mid - > func ;
}
2007-07-20 20:12:51 +04:00
return no_such_ioctl ;
}
static int no_such_ioctl_0 ( struct v4l2_int_device * d )
{
2007-08-30 16:20:40 +04:00
return - ENOIOCTLCMD ;
2007-07-19 00:59:15 +04:00
}
int v4l2_int_ioctl_0 ( struct v4l2_int_device * d , int cmd )
{
2007-07-20 20:12:51 +04:00
return ( ( v4l2_int_ioctl_func_0 * )
find_ioctl ( d - > u . slave , cmd ,
2007-08-30 16:20:38 +04:00
( v4l2_int_ioctl_func * ) no_such_ioctl_0 ) ) ( d ) ;
2007-07-20 20:12:51 +04:00
}
2008-10-18 19:28:36 +04:00
EXPORT_SYMBOL_GPL ( v4l2_int_ioctl_0 ) ;
2007-07-20 20:12:51 +04:00
static int no_such_ioctl_1 ( struct v4l2_int_device * d , void * arg )
{
2007-08-30 16:20:40 +04:00
return - ENOIOCTLCMD ;
2007-07-19 00:59:15 +04:00
}
int v4l2_int_ioctl_1 ( struct v4l2_int_device * d , int cmd , void * arg )
{
2007-07-20 20:12:51 +04:00
return ( ( v4l2_int_ioctl_func_1 * )
find_ioctl ( d - > u . slave , cmd ,
2007-08-30 16:20:38 +04:00
( v4l2_int_ioctl_func * ) no_such_ioctl_1 ) ) ( d , arg ) ;
2007-07-19 00:59:15 +04:00
}
2008-10-18 19:28:36 +04:00
EXPORT_SYMBOL_GPL ( v4l2_int_ioctl_1 ) ;
2008-03-31 16:08:08 +04:00
MODULE_LICENSE ( " GPL " ) ;