2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2010-03-23 09:25:26 -03:00
/*
* v4l2 - fh . c
*
* V4L2 file handles .
*
* Copyright ( C ) 2009 - - 2010 Nokia Corporation .
*
2012-10-28 06:44:17 -03:00
* Contact : Sakari Ailus < sakari . ailus @ iki . fi >
2010-03-23 09:25:26 -03:00
*/
# include <linux/bitops.h>
2011-01-08 09:36:04 -03:00
# include <linux/slab.h>
2011-08-01 15:26:38 -04:00
# include <linux/export.h>
2010-03-23 09:25:26 -03:00
# include <media/v4l2-dev.h>
# include <media/v4l2-fh.h>
2010-03-01 05:14:18 -03:00
# include <media/v4l2-event.h>
# include <media/v4l2-ioctl.h>
2016-02-11 21:41:29 -02:00
# include <media/v4l2-mc.h>
2010-03-23 09:25:26 -03:00
2011-06-13 17:44:42 -03:00
void v4l2_fh_init ( struct v4l2_fh * fh , struct video_device * vdev )
2010-03-23 09:25:26 -03:00
{
fh - > vdev = vdev ;
2011-03-12 08:54:43 -03:00
/* Inherit from video_device. May be overridden by the driver. */
fh - > ctrl_handler = vdev - > ctrl_handler ;
2010-03-23 09:25:26 -03:00
INIT_LIST_HEAD ( & fh - > list ) ;
set_bit ( V4L2_FL_USES_V4L2_FH , & fh - > vdev - > flags ) ;
2014-06-19 14:22:57 -03:00
/*
* determine_valid_ioctls ( ) does not know if struct v4l2_fh
* is used by this driver , but here we do . So enable the
* prio ioctls here .
*/
set_bit ( _IOC_NR ( VIDIOC_G_PRIORITY ) , vdev - > valid_ioctls ) ;
set_bit ( _IOC_NR ( VIDIOC_S_PRIORITY ) , vdev - > valid_ioctls ) ;
2010-12-29 13:36:50 -03:00
fh - > prio = V4L2_PRIORITY_UNSET ;
2011-06-13 17:44:42 -03:00
init_waitqueue_head ( & fh - > wait ) ;
INIT_LIST_HEAD ( & fh - > available ) ;
INIT_LIST_HEAD ( & fh - > subscribed ) ;
fh - > sequence = - 1 ;
2018-09-11 05:32:37 -04:00
mutex_init ( & fh - > subscribe_lock ) ;
2010-03-23 09:25:26 -03:00
}
EXPORT_SYMBOL_GPL ( v4l2_fh_init ) ;
void v4l2_fh_add ( struct v4l2_fh * fh )
{
unsigned long flags ;
2014-06-19 14:22:57 -03:00
v4l2_prio_open ( fh - > vdev - > prio , & fh - > prio ) ;
2010-03-23 09:25:26 -03:00
spin_lock_irqsave ( & fh - > vdev - > fh_lock , flags ) ;
list_add ( & fh - > list , & fh - > vdev - > fh_list ) ;
spin_unlock_irqrestore ( & fh - > vdev - > fh_lock , flags ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_fh_add ) ;
2011-01-08 09:36:04 -03:00
int v4l2_fh_open ( struct file * filp )
{
struct video_device * vdev = video_devdata ( filp ) ;
struct v4l2_fh * fh = kzalloc ( sizeof ( * fh ) , GFP_KERNEL ) ;
filp - > private_data = fh ;
if ( fh = = NULL )
return - ENOMEM ;
v4l2_fh_init ( fh , vdev ) ;
v4l2_fh_add ( fh ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l2_fh_open ) ;
2010-03-23 09:25:26 -03:00
void v4l2_fh_del ( struct v4l2_fh * fh )
{
unsigned long flags ;
spin_lock_irqsave ( & fh - > vdev - > fh_lock , flags ) ;
list_del_init ( & fh - > list ) ;
spin_unlock_irqrestore ( & fh - > vdev - > fh_lock , flags ) ;
2014-06-19 14:22:57 -03:00
v4l2_prio_close ( fh - > vdev - > prio , fh - > prio ) ;
2010-03-23 09:25:26 -03:00
}
EXPORT_SYMBOL_GPL ( v4l2_fh_del ) ;
void v4l2_fh_exit ( struct v4l2_fh * fh )
{
if ( fh - > vdev = = NULL )
return ;
2016-02-11 21:41:29 -02:00
v4l_disable_media_source ( fh - > vdev ) ;
2011-06-13 19:24:17 -03:00
v4l2_event_unsubscribe_all ( fh ) ;
2018-09-11 05:32:37 -04:00
mutex_destroy ( & fh - > subscribe_lock ) ;
2011-06-07 11:13:44 -03:00
fh - > vdev = NULL ;
2010-03-23 09:25:26 -03:00
}
EXPORT_SYMBOL_GPL ( v4l2_fh_exit ) ;
2011-01-08 09:36:04 -03:00
int v4l2_fh_release ( struct file * filp )
{
struct v4l2_fh * fh = filp - > private_data ;
if ( fh ) {
v4l2_fh_del ( fh ) ;
v4l2_fh_exit ( fh ) ;
kfree ( fh ) ;
2021-05-09 10:24:02 +02:00
filp - > private_data = NULL ;
2011-01-08 09:36:04 -03:00
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l2_fh_release ) ;
2011-01-08 09:38:02 -03:00
int v4l2_fh_is_singular ( struct v4l2_fh * fh )
{
unsigned long flags ;
int is_singular ;
if ( fh = = NULL | | fh - > vdev = = NULL )
return 0 ;
spin_lock_irqsave ( & fh - > vdev - > fh_lock , flags ) ;
is_singular = list_is_singular ( & fh - > list ) ;
spin_unlock_irqrestore ( & fh - > vdev - > fh_lock , flags ) ;
return is_singular ;
}
EXPORT_SYMBOL_GPL ( v4l2_fh_is_singular ) ;