2008-07-20 15:43:17 +04:00
/*
* Video capture interface for Linux version 2
*
* 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
* Authors : Alan Cox , < alan @ lxorguk . ukuu . org . uk > ( version 1 )
2008-07-20 15:43:17 +04:00
* Mauro Carvalho Chehab < mchehab @ infradead . org > ( version 2 )
*
* Fixes : 20000516 Claudio Matsuoka < claudio @ conectiva . com >
* - Added procfs support
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/kmod.h>
# include <linux/slab.h>
# include <asm/uaccess.h>
# include <media/v4l2-common.h>
2008-12-23 13:35:17 +03:00
# include <media/v4l2-device.h>
2008-12-30 12:58:20 +03:00
# include <media/v4l2-ioctl.h>
2008-07-20 15:43:17 +04:00
# define VIDEO_NUM_DEVICES 256
# define VIDEO_NAME "video4linux"
/*
* sysfs stuff
*/
static ssize_t show_index ( struct device * cd ,
struct device_attribute * attr , char * buf )
{
2008-12-20 03:28:27 +03:00
struct video_device * vdev = to_video_device ( cd ) ;
2008-08-23 14:48:38 +04:00
2008-12-20 03:28:27 +03:00
return sprintf ( buf , " %i \n " , vdev - > index ) ;
2008-07-20 15:43:17 +04:00
}
2012-06-22 13:37:38 +04:00
static ssize_t show_debug ( struct device * cd ,
struct device_attribute * attr , char * buf )
{
struct video_device * vdev = to_video_device ( cd ) ;
return sprintf ( buf , " %i \n " , vdev - > debug ) ;
}
static ssize_t set_debug ( struct device * cd , struct device_attribute * attr ,
const char * buf , size_t len )
{
struct video_device * vdev = to_video_device ( cd ) ;
int res = 0 ;
u16 value ;
res = kstrtou16 ( buf , 0 , & value ) ;
if ( res )
return res ;
vdev - > debug = value ;
return len ;
}
2008-07-20 15:43:17 +04:00
static ssize_t show_name ( struct device * cd ,
struct device_attribute * attr , char * buf )
{
2008-12-20 03:28:27 +03:00
struct video_device * vdev = to_video_device ( cd ) ;
2008-08-23 14:48:38 +04:00
2008-12-20 03:28:27 +03:00
return sprintf ( buf , " %.*s \n " , ( int ) sizeof ( vdev - > name ) , vdev - > name ) ;
2008-07-20 15:43:17 +04:00
}
static struct device_attribute video_device_attrs [ ] = {
__ATTR ( name , S_IRUGO , show_name , NULL ) ,
2012-06-22 13:37:38 +04:00
__ATTR ( debug , 0644 , show_debug , set_debug ) ,
2008-07-20 15:43:17 +04:00
__ATTR ( index , S_IRUGO , show_index , NULL ) ,
__ATTR_NULL
} ;
2008-08-30 00:31:35 +04:00
/*
* Active devices
*/
static struct video_device * video_device [ VIDEO_NUM_DEVICES ] ;
static DEFINE_MUTEX ( videodev_lock ) ;
2009-09-06 14:13:14 +04:00
static DECLARE_BITMAP ( devnode_nums [ VFL_TYPE_MAX ] , VIDEO_NUM_DEVICES ) ;
2008-08-30 00:31:35 +04:00
2009-09-07 10:40:24 +04:00
/* Device node utility functions */
/* Note: these utility functions all assume that vfl_type is in the range
[ 0 , VFL_TYPE_MAX - 1 ] . */
# ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* Return the bitmap corresponding to vfl_type. */
static inline unsigned long * devnode_bits ( int vfl_type )
{
/* Any types not assigned to fixed minor ranges must be mapped to
one single bitmap for the purposes of finding a free node number
since all those unassigned types use the same minor range . */
2010-08-06 19:48:00 +04:00
int idx = ( vfl_type > VFL_TYPE_RADIO ) ? VFL_TYPE_MAX - 1 : vfl_type ;
2009-09-07 10:40:24 +04:00
return devnode_nums [ idx ] ;
}
# else
/* Return the bitmap corresponding to vfl_type. */
static inline unsigned long * devnode_bits ( int vfl_type )
{
return devnode_nums [ vfl_type ] ;
}
# endif
/* Mark device node number vdev->num as used */
static inline void devnode_set ( struct video_device * vdev )
{
set_bit ( vdev - > num , devnode_bits ( vdev - > vfl_type ) ) ;
}
/* Mark device node number vdev->num as unused */
static inline void devnode_clear ( struct video_device * vdev )
{
clear_bit ( vdev - > num , devnode_bits ( vdev - > vfl_type ) ) ;
}
/* Try to find a free device node number in the range [from, to> */
static inline int devnode_find ( struct video_device * vdev , int from , int to )
{
return find_next_zero_bit ( devnode_bits ( vdev - > vfl_type ) , to , from ) ;
}
2008-07-20 15:43:17 +04:00
struct video_device * video_device_alloc ( void )
{
2008-08-23 14:48:38 +04:00
return kzalloc ( sizeof ( struct video_device ) , GFP_KERNEL ) ;
2008-07-20 15:43:17 +04:00
}
EXPORT_SYMBOL ( video_device_alloc ) ;
2008-12-20 03:28:27 +03:00
void video_device_release ( struct video_device * vdev )
2008-07-20 15:43:17 +04:00
{
2008-12-20 03:28:27 +03:00
kfree ( vdev ) ;
2008-07-20 15:43:17 +04:00
}
EXPORT_SYMBOL ( video_device_release ) ;
2008-12-20 03:28:27 +03:00
void video_device_release_empty ( struct video_device * vdev )
2008-08-23 12:47:41 +04:00
{
/* Do nothing */
/* Only valid when the video_device struct is a static. */
}
EXPORT_SYMBOL ( video_device_release_empty ) ;
2008-12-20 03:28:27 +03:00
static inline void video_get ( struct video_device * vdev )
2008-08-30 00:31:35 +04:00
{
2008-12-20 03:28:27 +03:00
get_device ( & vdev - > dev ) ;
}
static inline void video_put ( struct video_device * vdev )
{
put_device ( & vdev - > dev ) ;
}
/* Called when the last user of the video device exits. */
static void v4l2_device_release ( struct device * cd )
{
struct video_device * vdev = to_video_device ( cd ) ;
2011-03-12 12:37:19 +03:00
struct v4l2_device * v4l2_dev = vdev - > v4l2_dev ;
2008-08-30 00:31:35 +04:00
mutex_lock ( & videodev_lock ) ;
2011-12-06 12:33:03 +04:00
if ( WARN_ON ( video_device [ vdev - > minor ] ! = vdev ) ) {
2008-12-20 03:28:27 +03:00
/* should not happen */
2011-12-06 12:33:03 +04:00
mutex_unlock ( & videodev_lock ) ;
2008-08-30 16:40:47 +04:00
return ;
}
2008-08-30 00:31:35 +04:00
/* Free up this device for reuse */
2008-12-20 03:28:27 +03:00
video_device [ vdev - > minor ] = NULL ;
2008-08-30 00:31:35 +04:00
2008-12-20 03:28:27 +03:00
/* Delete the cdev on this minor as well */
cdev_del ( vdev - > cdev ) ;
/* Just in case some driver tries to access this from
the release ( ) callback . */
vdev - > cdev = NULL ;
2008-08-30 00:31:35 +04:00
2009-09-06 14:13:14 +04:00
/* Mark device node number as free */
2009-09-07 10:40:24 +04:00
devnode_clear ( vdev ) ;
2008-08-30 00:31:35 +04:00
2008-12-20 03:28:27 +03:00
mutex_unlock ( & videodev_lock ) ;
2008-07-20 15:43:17 +04:00
2011-06-15 12:20:34 +04:00
# if defined(CONFIG_MEDIA_CONTROLLER)
2011-12-06 12:33:03 +04:00
if ( v4l2_dev & & v4l2_dev - > mdev & &
2011-06-15 12:20:34 +04:00
vdev - > vfl_type ! = VFL_TYPE_SUBDEV )
media_device_unregister_entity ( & vdev - > entity ) ;
# endif
2011-09-06 17:23:18 +04:00
/* Do not call v4l2_device_put if there is no release callback set.
* Drivers that have no v4l2_device release callback might free the
* v4l2_dev instance in the video_device release callback below , so we
* must perform this check here .
*
* TODO : In the long run all drivers that use v4l2_device should use the
* v4l2_device release callback . This check will then be unnecessary .
*/
2011-10-13 00:59:26 +04:00
if ( v4l2_dev & & v4l2_dev - > release = = NULL )
2011-09-06 17:23:18 +04:00
v4l2_dev = NULL ;
2008-12-20 03:28:27 +03:00
/* Release video_device and perform other
cleanups as needed . */
vdev - > release ( vdev ) ;
2011-03-12 12:37:19 +03:00
/* Decrease v4l2_device refcount */
if ( v4l2_dev )
v4l2_device_put ( v4l2_dev ) ;
2008-07-20 15:43:17 +04:00
}
static struct class video_class = {
. name = VIDEO_NAME ,
. dev_attrs = video_device_attrs ,
} ;
struct video_device * video_devdata ( struct file * file )
{
return video_device [ iminor ( file - > f_path . dentry - > d_inode ) ] ;
}
EXPORT_SYMBOL ( video_devdata ) ;
2010-12-29 16:05:02 +03:00
/* Priority handling */
static inline bool prio_is_valid ( enum v4l2_priority prio )
{
return prio = = V4L2_PRIORITY_BACKGROUND | |
prio = = V4L2_PRIORITY_INTERACTIVE | |
prio = = V4L2_PRIORITY_RECORD ;
}
void v4l2_prio_init ( struct v4l2_prio_state * global )
{
memset ( global , 0 , sizeof ( * global ) ) ;
}
EXPORT_SYMBOL ( v4l2_prio_init ) ;
int v4l2_prio_change ( struct v4l2_prio_state * global , enum v4l2_priority * local ,
enum v4l2_priority new )
{
if ( ! prio_is_valid ( new ) )
return - EINVAL ;
if ( * local = = new )
return 0 ;
atomic_inc ( & global - > prios [ new ] ) ;
if ( prio_is_valid ( * local ) )
atomic_dec ( & global - > prios [ * local ] ) ;
* local = new ;
return 0 ;
}
EXPORT_SYMBOL ( v4l2_prio_change ) ;
void v4l2_prio_open ( struct v4l2_prio_state * global , enum v4l2_priority * local )
{
v4l2_prio_change ( global , local , V4L2_PRIORITY_DEFAULT ) ;
}
EXPORT_SYMBOL ( v4l2_prio_open ) ;
void v4l2_prio_close ( struct v4l2_prio_state * global , enum v4l2_priority local )
{
if ( prio_is_valid ( local ) )
atomic_dec ( & global - > prios [ local ] ) ;
}
EXPORT_SYMBOL ( v4l2_prio_close ) ;
enum v4l2_priority v4l2_prio_max ( struct v4l2_prio_state * global )
{
if ( atomic_read ( & global - > prios [ V4L2_PRIORITY_RECORD ] ) > 0 )
return V4L2_PRIORITY_RECORD ;
if ( atomic_read ( & global - > prios [ V4L2_PRIORITY_INTERACTIVE ] ) > 0 )
return V4L2_PRIORITY_INTERACTIVE ;
if ( atomic_read ( & global - > prios [ V4L2_PRIORITY_BACKGROUND ] ) > 0 )
return V4L2_PRIORITY_BACKGROUND ;
return V4L2_PRIORITY_UNSET ;
}
EXPORT_SYMBOL ( v4l2_prio_max ) ;
int v4l2_prio_check ( struct v4l2_prio_state * global , enum v4l2_priority local )
{
return ( local < v4l2_prio_max ( global ) ) ? - EBUSY : 0 ;
}
EXPORT_SYMBOL ( v4l2_prio_check ) ;
2008-12-20 03:28:27 +03:00
static ssize_t v4l2_read ( struct file * filp , char __user * buf ,
size_t sz , loff_t * off )
{
struct video_device * vdev = video_devdata ( filp ) ;
2010-11-26 12:43:51 +03:00
int ret = - ENODEV ;
2008-12-20 03:28:27 +03:00
if ( ! vdev - > fops - > read )
return - EINVAL ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) & &
mutex_lock_interruptible ( vdev - > lock ) )
2010-11-26 12:43:51 +03:00
return - ERESTARTSYS ;
2010-09-26 15:47:38 +04:00
if ( video_is_registered ( vdev ) )
ret = vdev - > fops - > read ( filp , buf , sz , off ) ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) )
2010-09-26 15:47:38 +04:00
mutex_unlock ( vdev - > lock ) ;
2012-06-09 19:13:29 +04:00
if ( vdev - > debug )
printk ( KERN_DEBUG " %s: read: %zd (%d) \n " ,
video_device_node_name ( vdev ) , sz , ret ) ;
2010-09-26 15:47:38 +04:00
return ret ;
2008-12-20 03:28:27 +03:00
}
static ssize_t v4l2_write ( struct file * filp , const char __user * buf ,
size_t sz , loff_t * off )
{
struct video_device * vdev = video_devdata ( filp ) ;
2010-11-26 12:43:51 +03:00
int ret = - ENODEV ;
2008-12-20 03:28:27 +03:00
if ( ! vdev - > fops - > write )
return - EINVAL ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) & &
mutex_lock_interruptible ( vdev - > lock ) )
2010-11-26 12:43:51 +03:00
return - ERESTARTSYS ;
2010-09-26 15:47:38 +04:00
if ( video_is_registered ( vdev ) )
ret = vdev - > fops - > write ( filp , buf , sz , off ) ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) )
2010-09-26 15:47:38 +04:00
mutex_unlock ( vdev - > lock ) ;
2012-06-09 19:13:29 +04:00
if ( vdev - > debug )
printk ( KERN_DEBUG " %s: write: %zd (%d) \n " ,
video_device_node_name ( vdev ) , sz , ret ) ;
2010-09-26 15:47:38 +04:00
return ret ;
2008-12-20 03:28:27 +03:00
}
static unsigned int v4l2_poll ( struct file * filp , struct poll_table_struct * poll )
{
struct video_device * vdev = video_devdata ( filp ) ;
2010-11-26 12:43:51 +03:00
int ret = POLLERR | POLLHUP ;
2010-09-26 15:47:38 +04:00
if ( ! vdev - > fops - > poll )
2010-11-26 12:43:51 +03:00
return DEFAULT_POLLMASK ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) )
2010-09-26 15:47:38 +04:00
mutex_lock ( vdev - > lock ) ;
if ( video_is_registered ( vdev ) )
ret = vdev - > fops - > poll ( filp , poll ) ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) )
2010-09-26 15:47:38 +04:00
mutex_unlock ( vdev - > lock ) ;
2012-06-09 19:13:29 +04:00
if ( vdev - > debug )
printk ( KERN_DEBUG " %s: poll: %08x \n " ,
video_device_node_name ( vdev ) , ret ) ;
2010-09-26 15:47:38 +04:00
return ret ;
2008-12-20 03:28:27 +03:00
}
2010-07-04 02:15:09 +04:00
static long v4l2_ioctl ( struct file * filp , unsigned int cmd , unsigned long arg )
2008-12-20 03:28:27 +03:00
{
struct video_device * vdev = video_devdata ( filp ) ;
2010-10-09 23:43:40 +04:00
int ret = - ENODEV ;
2008-12-20 03:28:27 +03:00
2010-07-04 02:15:09 +04:00
if ( vdev - > fops - > unlocked_ioctl ) {
2012-06-22 14:29:35 +04:00
struct mutex * lock = v4l2_ioctl_get_lock ( vdev , cmd ) ;
2012-05-10 09:51:31 +04:00
2012-06-22 14:29:35 +04:00
if ( lock & & mutex_lock_interruptible ( lock ) )
return - ERESTARTSYS ;
2010-10-09 23:43:40 +04:00
if ( video_is_registered ( vdev ) )
ret = vdev - > fops - > unlocked_ioctl ( filp , cmd , arg ) ;
2012-06-22 14:29:35 +04:00
if ( lock )
mutex_unlock ( lock ) ;
2010-07-04 02:15:09 +04:00
} else if ( vdev - > fops - > ioctl ) {
2010-11-26 12:47:28 +03:00
/* This code path is a replacement for the BKL. It is a major
* hack but it will have to do for those drivers that are not
* yet converted to use unlocked_ioctl .
*
* There are two options : if the driver implements struct
* v4l2_device , then the lock defined there is used to
* serialize the ioctls . Otherwise the v4l2 core lock defined
* below is used . This lock is really bad since it serializes
* completely independent devices .
*
* Both variants suffer from the same problem : if the driver
* sleeps , then it blocks all ioctls since the lock is still
* held . This is very common for VIDIOC_DQBUF since that
* normally waits for a frame to arrive . As a result any other
* ioctl calls will proceed very , very slowly since each call
* will have to wait for the VIDIOC_QBUF to finish . Things that
* should take 0.01 s may now take 10 - 20 seconds .
*
* The workaround is to * not * take the lock for VIDIOC_DQBUF .
* This actually works OK for videobuf - based drivers , since
* videobuf will take its own internal lock .
*/
2010-10-27 16:30:32 +04:00
static DEFINE_MUTEX ( v4l2_ioctl_mutex ) ;
2010-11-26 12:47:28 +03:00
struct mutex * m = vdev - > v4l2_dev ?
& vdev - > v4l2_dev - > ioctl_lock : & v4l2_ioctl_mutex ;
2010-10-27 16:30:32 +04:00
2010-11-26 12:47:28 +03:00
if ( cmd ! = VIDIOC_DQBUF & & mutex_lock_interruptible ( m ) )
return - ERESTARTSYS ;
2010-10-09 23:43:40 +04:00
if ( video_is_registered ( vdev ) )
ret = vdev - > fops - > ioctl ( filp , cmd , arg ) ;
2010-11-26 12:47:28 +03:00
if ( cmd ! = VIDIOC_DQBUF )
mutex_unlock ( m ) ;
2010-07-04 02:15:09 +04:00
} else
ret = - ENOTTY ;
2008-12-20 03:28:27 +03:00
2010-07-04 02:15:09 +04:00
return ret ;
2008-12-20 03:28:27 +03:00
}
2011-05-06 12:20:09 +04:00
# ifdef CONFIG_MMU
# define v4l2_get_unmapped_area NULL
# else
static unsigned long v4l2_get_unmapped_area ( struct file * filp ,
unsigned long addr , unsigned long len , unsigned long pgoff ,
unsigned long flags )
{
struct video_device * vdev = video_devdata ( filp ) ;
2012-06-09 19:13:29 +04:00
int ret ;
2011-05-06 12:20:09 +04:00
if ( ! vdev - > fops - > get_unmapped_area )
return - ENOSYS ;
if ( ! video_is_registered ( vdev ) )
return - ENODEV ;
2012-06-09 19:13:29 +04:00
ret = vdev - > fops - > get_unmapped_area ( filp , addr , len , pgoff , flags ) ;
if ( vdev - > debug )
printk ( KERN_DEBUG " %s: get_unmapped_area (%d) \n " ,
video_device_node_name ( vdev ) , ret ) ;
return ret ;
2011-05-06 12:20:09 +04:00
}
# endif
2008-12-20 03:28:27 +03:00
static int v4l2_mmap ( struct file * filp , struct vm_area_struct * vm )
{
struct video_device * vdev = video_devdata ( filp ) ;
2010-09-26 15:47:38 +04:00
int ret = - ENODEV ;
if ( ! vdev - > fops - > mmap )
return ret ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) & &
mutex_lock_interruptible ( vdev - > lock ) )
2010-11-26 12:43:51 +03:00
return - ERESTARTSYS ;
2010-09-26 15:47:38 +04:00
if ( video_is_registered ( vdev ) )
ret = vdev - > fops - > mmap ( filp , vm ) ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) )
2010-09-26 15:47:38 +04:00
mutex_unlock ( vdev - > lock ) ;
2012-06-09 19:13:29 +04:00
if ( vdev - > debug )
printk ( KERN_DEBUG " %s: mmap (%d) \n " ,
video_device_node_name ( vdev ) , ret ) ;
2010-09-26 15:47:38 +04:00
return ret ;
2008-12-20 03:28:27 +03:00
}
/* Override for the open function */
static int v4l2_open ( struct inode * inode , struct file * filp )
{
struct video_device * vdev ;
2009-03-30 03:19:38 +04:00
int ret = 0 ;
2008-12-20 03:28:27 +03:00
/* Check if the video device is available */
mutex_lock ( & videodev_lock ) ;
vdev = video_devdata ( filp ) ;
2010-09-26 15:47:38 +04:00
/* return ENODEV if the video device has already been removed. */
2010-11-26 12:54:53 +03:00
if ( vdev = = NULL | | ! video_is_registered ( vdev ) ) {
2008-12-20 03:28:27 +03:00
mutex_unlock ( & videodev_lock ) ;
return - ENODEV ;
}
/* and increase the device refcount */
video_get ( vdev ) ;
mutex_unlock ( & videodev_lock ) ;
2010-09-26 15:47:38 +04:00
if ( vdev - > fops - > open ) {
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) & &
mutex_lock_interruptible ( vdev - > lock ) ) {
2010-11-26 12:43:51 +03:00
ret = - ERESTARTSYS ;
goto err ;
}
2010-09-26 15:47:38 +04:00
if ( video_is_registered ( vdev ) )
ret = vdev - > fops - > open ( filp ) ;
else
ret = - ENODEV ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) )
2010-09-26 15:47:38 +04:00
mutex_unlock ( vdev - > lock ) ;
}
2009-03-30 03:19:38 +04:00
2010-11-26 12:43:51 +03:00
err :
2012-06-09 19:13:29 +04:00
if ( vdev - > debug )
printk ( KERN_DEBUG " %s: open (%d) \n " ,
video_device_node_name ( vdev ) , ret ) ;
2012-07-26 14:59:04 +04:00
/* decrease the refcount in case of an error */
if ( ret )
video_put ( vdev ) ;
2008-12-20 03:28:27 +03:00
return ret ;
}
/* Override for the release function */
static int v4l2_release ( struct inode * inode , struct file * filp )
{
struct video_device * vdev = video_devdata ( filp ) ;
2009-03-30 03:19:38 +04:00
int ret = 0 ;
2010-09-26 15:47:38 +04:00
if ( vdev - > fops - > release ) {
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) )
2010-09-26 15:47:38 +04:00
mutex_lock ( vdev - > lock ) ;
2009-03-30 03:19:38 +04:00
vdev - > fops - > release ( filp ) ;
2012-05-10 11:57:22 +04:00
if ( test_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) )
2010-09-26 15:47:38 +04:00
mutex_unlock ( vdev - > lock ) ;
}
2012-06-09 19:13:29 +04:00
if ( vdev - > debug )
printk ( KERN_DEBUG " %s: release \n " ,
video_device_node_name ( vdev ) ) ;
2012-07-26 14:59:04 +04:00
/* decrease the refcount unconditionally since the release()
return value is ignored . */
video_put ( vdev ) ;
2008-12-20 03:28:27 +03:00
return ret ;
}
static const struct file_operations v4l2_fops = {
. owner = THIS_MODULE ,
. read = v4l2_read ,
. write = v4l2_write ,
. open = v4l2_open ,
2011-05-06 12:20:09 +04:00
. get_unmapped_area = v4l2_get_unmapped_area ,
2008-12-20 03:28:27 +03:00
. mmap = v4l2_mmap ,
2010-07-04 02:15:09 +04:00
. unlocked_ioctl = v4l2_ioctl ,
2008-12-20 03:28:27 +03:00
# ifdef CONFIG_COMPAT
2008-12-30 12:42:40 +03:00
. compat_ioctl = v4l2_compat_ioctl32 ,
2008-12-20 03:28:27 +03:00
# endif
. release = v4l2_release ,
. poll = v4l2_poll ,
. llseek = no_llseek ,
} ;
2008-07-20 15:43:17 +04:00
/**
2009-06-19 18:32:56 +04:00
* get_index - assign stream index number based on parent device
2008-12-20 03:28:27 +03:00
* @ vdev : video_device to assign index number to , vdev - > parent should be assigned
2008-07-20 15:43:17 +04:00
*
2008-12-20 03:28:27 +03:00
* Note that when this is called the new device has not yet been registered
2009-06-19 18:32:56 +04:00
* in the video_device array , but it was able to obtain a minor number .
2008-07-20 15:43:17 +04:00
*
2009-06-19 18:32:56 +04:00
* This means that we can always obtain a free stream index number since
* the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
* use of the video_device array .
*
* Returns a free index number .
2008-07-20 15:43:17 +04:00
*/
2009-06-19 18:32:56 +04:00
static int get_index ( struct video_device * vdev )
2008-07-20 15:43:17 +04:00
{
2009-02-14 17:31:01 +03:00
/* This can be static since this function is called with the global
videodev_lock held . */
static DECLARE_BITMAP ( used , VIDEO_NUM_DEVICES ) ;
2008-07-20 15:43:17 +04:00
int i ;
2009-06-19 18:32:56 +04:00
/* Some drivers do not set the parent. In that case always return 0. */
2008-12-19 15:10:56 +03:00
if ( vdev - > parent = = NULL )
2009-06-19 18:32:56 +04:00
return 0 ;
2009-02-14 17:31:01 +03:00
bitmap_zero ( used , VIDEO_NUM_DEVICES ) ;
2008-12-19 15:10:56 +03:00
2008-07-20 15:43:17 +04:00
for ( i = 0 ; i < VIDEO_NUM_DEVICES ; i + + ) {
if ( video_device [ i ] ! = NULL & &
2008-07-20 13:31:39 +04:00
video_device [ i ] - > parent = = vdev - > parent ) {
2009-02-14 17:31:01 +03:00
set_bit ( video_device [ i ] - > index , used ) ;
2008-07-20 15:43:17 +04:00
}
}
2009-06-19 18:32:56 +04:00
return find_first_zero_bit ( used , VIDEO_NUM_DEVICES ) ;
2008-07-20 15:43:17 +04:00
}
2012-05-10 12:36:00 +04:00
# define SET_VALID_IOCTL(ops, cmd, op) \
if ( ops - > op ) \
set_bit ( _IOC_NR ( cmd ) , valid_ioctls )
/* This determines which ioctls are actually implemented in the driver.
It ' s a one - time thing which simplifies video_ioctl2 as it can just do
a bit test .
Note that drivers can override this by setting bits to 1 in
vdev - > valid_ioctls . If an ioctl is marked as 1 when this function is
called , then that ioctl will actually be marked as unimplemented .
It does that by first setting up the local valid_ioctls bitmap , and
at the end do a :
vdev - > valid_ioctls = valid_ioctls & ~ ( vdev - > valid_ioctls )
*/
static void determine_valid_ioctls ( struct video_device * vdev )
{
DECLARE_BITMAP ( valid_ioctls , BASE_VIDIOC_PRIVATE ) ;
const struct v4l2_ioctl_ops * ops = vdev - > ioctl_ops ;
bitmap_zero ( valid_ioctls , BASE_VIDIOC_PRIVATE ) ;
SET_VALID_IOCTL ( ops , VIDIOC_QUERYCAP , vidioc_querycap ) ;
if ( ops - > vidioc_g_priority | |
test_bit ( V4L2_FL_USE_FH_PRIO , & vdev - > flags ) )
set_bit ( _IOC_NR ( VIDIOC_G_PRIORITY ) , valid_ioctls ) ;
if ( ops - > vidioc_s_priority | |
test_bit ( V4L2_FL_USE_FH_PRIO , & vdev - > flags ) )
set_bit ( _IOC_NR ( VIDIOC_S_PRIORITY ) , valid_ioctls ) ;
if ( ops - > vidioc_enum_fmt_vid_cap | |
ops - > vidioc_enum_fmt_vid_out | |
ops - > vidioc_enum_fmt_vid_cap_mplane | |
ops - > vidioc_enum_fmt_vid_out_mplane | |
ops - > vidioc_enum_fmt_vid_overlay | |
ops - > vidioc_enum_fmt_type_private )
set_bit ( _IOC_NR ( VIDIOC_ENUM_FMT ) , valid_ioctls ) ;
if ( ops - > vidioc_g_fmt_vid_cap | |
ops - > vidioc_g_fmt_vid_out | |
ops - > vidioc_g_fmt_vid_cap_mplane | |
ops - > vidioc_g_fmt_vid_out_mplane | |
ops - > vidioc_g_fmt_vid_overlay | |
ops - > vidioc_g_fmt_vbi_cap | |
ops - > vidioc_g_fmt_vid_out_overlay | |
ops - > vidioc_g_fmt_vbi_out | |
ops - > vidioc_g_fmt_sliced_vbi_cap | |
ops - > vidioc_g_fmt_sliced_vbi_out | |
ops - > vidioc_g_fmt_type_private )
set_bit ( _IOC_NR ( VIDIOC_G_FMT ) , valid_ioctls ) ;
if ( ops - > vidioc_s_fmt_vid_cap | |
ops - > vidioc_s_fmt_vid_out | |
ops - > vidioc_s_fmt_vid_cap_mplane | |
ops - > vidioc_s_fmt_vid_out_mplane | |
ops - > vidioc_s_fmt_vid_overlay | |
ops - > vidioc_s_fmt_vbi_cap | |
ops - > vidioc_s_fmt_vid_out_overlay | |
ops - > vidioc_s_fmt_vbi_out | |
ops - > vidioc_s_fmt_sliced_vbi_cap | |
ops - > vidioc_s_fmt_sliced_vbi_out | |
ops - > vidioc_s_fmt_type_private )
set_bit ( _IOC_NR ( VIDIOC_S_FMT ) , valid_ioctls ) ;
if ( ops - > vidioc_try_fmt_vid_cap | |
ops - > vidioc_try_fmt_vid_out | |
ops - > vidioc_try_fmt_vid_cap_mplane | |
ops - > vidioc_try_fmt_vid_out_mplane | |
ops - > vidioc_try_fmt_vid_overlay | |
ops - > vidioc_try_fmt_vbi_cap | |
ops - > vidioc_try_fmt_vid_out_overlay | |
ops - > vidioc_try_fmt_vbi_out | |
ops - > vidioc_try_fmt_sliced_vbi_cap | |
ops - > vidioc_try_fmt_sliced_vbi_out | |
ops - > vidioc_try_fmt_type_private )
set_bit ( _IOC_NR ( VIDIOC_TRY_FMT ) , valid_ioctls ) ;
SET_VALID_IOCTL ( ops , VIDIOC_REQBUFS , vidioc_reqbufs ) ;
SET_VALID_IOCTL ( ops , VIDIOC_QUERYBUF , vidioc_querybuf ) ;
SET_VALID_IOCTL ( ops , VIDIOC_QBUF , vidioc_qbuf ) ;
SET_VALID_IOCTL ( ops , VIDIOC_DQBUF , vidioc_dqbuf ) ;
SET_VALID_IOCTL ( ops , VIDIOC_OVERLAY , vidioc_overlay ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_FBUF , vidioc_g_fbuf ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_FBUF , vidioc_s_fbuf ) ;
SET_VALID_IOCTL ( ops , VIDIOC_STREAMON , vidioc_streamon ) ;
SET_VALID_IOCTL ( ops , VIDIOC_STREAMOFF , vidioc_streamoff ) ;
if ( vdev - > tvnorms )
set_bit ( _IOC_NR ( VIDIOC_ENUMSTD ) , valid_ioctls ) ;
if ( ops - > vidioc_g_std | | vdev - > current_norm )
set_bit ( _IOC_NR ( VIDIOC_G_STD ) , valid_ioctls ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_STD , vidioc_s_std ) ;
SET_VALID_IOCTL ( ops , VIDIOC_QUERYSTD , vidioc_querystd ) ;
SET_VALID_IOCTL ( ops , VIDIOC_ENUMINPUT , vidioc_enum_input ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_INPUT , vidioc_g_input ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_INPUT , vidioc_s_input ) ;
SET_VALID_IOCTL ( ops , VIDIOC_ENUMOUTPUT , vidioc_enum_output ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_OUTPUT , vidioc_g_output ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_OUTPUT , vidioc_s_output ) ;
/* Note: the control handler can also be passed through the filehandle,
and that can ' t be tested here . If the bit for these control ioctls
is set , then the ioctl is valid . But if it is 0 , then it can still
be valid if the filehandle passed the control handler . */
if ( vdev - > ctrl_handler | | ops - > vidioc_queryctrl )
set_bit ( _IOC_NR ( VIDIOC_QUERYCTRL ) , valid_ioctls ) ;
if ( vdev - > ctrl_handler | | ops - > vidioc_g_ctrl | | ops - > vidioc_g_ext_ctrls )
set_bit ( _IOC_NR ( VIDIOC_G_CTRL ) , valid_ioctls ) ;
if ( vdev - > ctrl_handler | | ops - > vidioc_s_ctrl | | ops - > vidioc_s_ext_ctrls )
set_bit ( _IOC_NR ( VIDIOC_S_CTRL ) , valid_ioctls ) ;
if ( vdev - > ctrl_handler | | ops - > vidioc_g_ext_ctrls )
set_bit ( _IOC_NR ( VIDIOC_G_EXT_CTRLS ) , valid_ioctls ) ;
if ( vdev - > ctrl_handler | | ops - > vidioc_s_ext_ctrls )
set_bit ( _IOC_NR ( VIDIOC_S_EXT_CTRLS ) , valid_ioctls ) ;
if ( vdev - > ctrl_handler | | ops - > vidioc_try_ext_ctrls )
set_bit ( _IOC_NR ( VIDIOC_TRY_EXT_CTRLS ) , valid_ioctls ) ;
if ( vdev - > ctrl_handler | | ops - > vidioc_querymenu )
set_bit ( _IOC_NR ( VIDIOC_QUERYMENU ) , valid_ioctls ) ;
SET_VALID_IOCTL ( ops , VIDIOC_ENUMAUDIO , vidioc_enumaudio ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_AUDIO , vidioc_g_audio ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_AUDIO , vidioc_s_audio ) ;
SET_VALID_IOCTL ( ops , VIDIOC_ENUMAUDOUT , vidioc_enumaudout ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_AUDOUT , vidioc_g_audout ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_AUDOUT , vidioc_s_audout ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_MODULATOR , vidioc_g_modulator ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_MODULATOR , vidioc_s_modulator ) ;
if ( ops - > vidioc_g_crop | | ops - > vidioc_g_selection )
set_bit ( _IOC_NR ( VIDIOC_G_CROP ) , valid_ioctls ) ;
if ( ops - > vidioc_s_crop | | ops - > vidioc_s_selection )
set_bit ( _IOC_NR ( VIDIOC_S_CROP ) , valid_ioctls ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_SELECTION , vidioc_g_selection ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_SELECTION , vidioc_s_selection ) ;
if ( ops - > vidioc_cropcap | | ops - > vidioc_g_selection )
set_bit ( _IOC_NR ( VIDIOC_CROPCAP ) , valid_ioctls ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_JPEGCOMP , vidioc_g_jpegcomp ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_JPEGCOMP , vidioc_s_jpegcomp ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_ENC_INDEX , vidioc_g_enc_index ) ;
SET_VALID_IOCTL ( ops , VIDIOC_ENCODER_CMD , vidioc_encoder_cmd ) ;
SET_VALID_IOCTL ( ops , VIDIOC_TRY_ENCODER_CMD , vidioc_try_encoder_cmd ) ;
SET_VALID_IOCTL ( ops , VIDIOC_DECODER_CMD , vidioc_decoder_cmd ) ;
SET_VALID_IOCTL ( ops , VIDIOC_TRY_DECODER_CMD , vidioc_try_decoder_cmd ) ;
2012-07-19 15:49:25 +04:00
if ( ops - > vidioc_g_parm | | ( vdev - > vfl_type = = VFL_TYPE_GRABBER & &
( ops - > vidioc_g_std | | vdev - > tvnorms ) ) )
2012-05-10 12:36:00 +04:00
set_bit ( _IOC_NR ( VIDIOC_G_PARM ) , valid_ioctls ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_PARM , vidioc_s_parm ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_TUNER , vidioc_g_tuner ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_TUNER , vidioc_s_tuner ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_FREQUENCY , vidioc_g_frequency ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_FREQUENCY , vidioc_s_frequency ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_SLICED_VBI_CAP , vidioc_g_sliced_vbi_cap ) ;
SET_VALID_IOCTL ( ops , VIDIOC_LOG_STATUS , vidioc_log_status ) ;
# ifdef CONFIG_VIDEO_ADV_DEBUG
SET_VALID_IOCTL ( ops , VIDIOC_DBG_G_REGISTER , vidioc_g_register ) ;
SET_VALID_IOCTL ( ops , VIDIOC_DBG_S_REGISTER , vidioc_s_register ) ;
# endif
SET_VALID_IOCTL ( ops , VIDIOC_DBG_G_CHIP_IDENT , vidioc_g_chip_ident ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_HW_FREQ_SEEK , vidioc_s_hw_freq_seek ) ;
SET_VALID_IOCTL ( ops , VIDIOC_ENUM_FRAMESIZES , vidioc_enum_framesizes ) ;
SET_VALID_IOCTL ( ops , VIDIOC_ENUM_FRAMEINTERVALS , vidioc_enum_frameintervals ) ;
SET_VALID_IOCTL ( ops , VIDIOC_ENUM_DV_PRESETS , vidioc_enum_dv_presets ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_DV_PRESET , vidioc_s_dv_preset ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_DV_PRESET , vidioc_g_dv_preset ) ;
SET_VALID_IOCTL ( ops , VIDIOC_QUERY_DV_PRESET , vidioc_query_dv_preset ) ;
SET_VALID_IOCTL ( ops , VIDIOC_S_DV_TIMINGS , vidioc_s_dv_timings ) ;
SET_VALID_IOCTL ( ops , VIDIOC_G_DV_TIMINGS , vidioc_g_dv_timings ) ;
2012-06-07 19:32:07 +04:00
SET_VALID_IOCTL ( ops , VIDIOC_ENUM_DV_TIMINGS , vidioc_enum_dv_timings ) ;
SET_VALID_IOCTL ( ops , VIDIOC_QUERY_DV_TIMINGS , vidioc_query_dv_timings ) ;
2012-07-11 16:12:45 +04:00
SET_VALID_IOCTL ( ops , VIDIOC_DV_TIMINGS_CAP , vidioc_dv_timings_cap ) ;
2012-05-10 12:36:00 +04:00
/* yes, really vidioc_subscribe_event */
SET_VALID_IOCTL ( ops , VIDIOC_DQEVENT , vidioc_subscribe_event ) ;
SET_VALID_IOCTL ( ops , VIDIOC_SUBSCRIBE_EVENT , vidioc_subscribe_event ) ;
SET_VALID_IOCTL ( ops , VIDIOC_UNSUBSCRIBE_EVENT , vidioc_unsubscribe_event ) ;
SET_VALID_IOCTL ( ops , VIDIOC_CREATE_BUFS , vidioc_create_bufs ) ;
SET_VALID_IOCTL ( ops , VIDIOC_PREPARE_BUF , vidioc_prepare_buf ) ;
2012-07-05 13:37:08 +04:00
if ( ops - > vidioc_enum_freq_bands | | ops - > vidioc_g_tuner | | ops - > vidioc_g_modulator )
set_bit ( _IOC_NR ( VIDIOC_ENUM_FREQ_BANDS ) , valid_ioctls ) ;
2012-05-10 12:36:00 +04:00
bitmap_andnot ( vdev - > valid_ioctls , valid_ioctls , vdev - > valid_ioctls ,
BASE_VIDIOC_PRIVATE ) ;
}
2008-07-20 15:43:17 +04:00
/**
2009-12-09 14:38:49 +03:00
* __video_register_device - register video4linux devices
2008-12-20 03:28:27 +03:00
* @ vdev : video device structure we want to register
2008-07-20 15:43:17 +04:00
* @ type : type of device to register
2009-09-06 14:13:14 +04:00
* @ nr : which device node number ( 0 = = / dev / video0 , 1 = = / dev / video1 , . . .
2008-07-20 15:43:17 +04:00
* - 1 = = first free )
2009-09-06 14:54:00 +04:00
* @ warn_if_nr_in_use : warn if the desired device node number
* was already in use and another number was chosen instead .
2009-12-09 14:38:49 +03:00
* @ owner : module that owns the video device node
2008-07-20 15:43:17 +04:00
*
2009-09-06 14:13:14 +04:00
* The registration code assigns minor numbers and device node numbers
* based on the requested type and registers the new device node with
* the kernel .
2010-12-31 17:47:23 +03:00
*
* This function assumes that struct video_device was zeroed when it
* was allocated and does not contain any stale date .
*
2009-09-06 14:13:14 +04:00
* An error is returned if no free minor or device node number could be
* found , or if the registration of the device node failed .
2008-07-20 15:43:17 +04:00
*
* Zero is returned on success .
*
* Valid types are
*
* % VFL_TYPE_GRABBER - A frame grabber
*
* % VFL_TYPE_VBI - Vertical blank data ( undecoded )
*
* % VFL_TYPE_RADIO - A radio card
2009-12-09 14:38:49 +03:00
*
* % VFL_TYPE_SUBDEV - A subdevice
2008-07-20 15:43:17 +04:00
*/
2009-12-09 14:38:49 +03:00
int __video_register_device ( struct video_device * vdev , int type , int nr ,
int warn_if_nr_in_use , struct module * owner )
2008-07-20 15:43:17 +04:00
{
int i = 0 ;
int ret ;
2008-10-04 15:36:54 +04:00
int minor_offset = 0 ;
int minor_cnt = VIDEO_NUM_DEVICES ;
const char * name_base ;
2008-07-20 15:43:17 +04:00
2008-12-20 03:28:27 +03:00
/* A minor value of -1 marks this video device as never
having been registered */
2009-03-04 00:51:52 +03:00
vdev - > minor = - 1 ;
2008-08-22 23:41:03 +04:00
2008-12-20 03:28:27 +03:00
/* the release callback MUST be present */
2011-12-06 12:33:03 +04:00
if ( WARN_ON ( ! vdev - > release ) )
2008-09-04 00:11:53 +04:00
return - EINVAL ;
2010-03-23 15:25:26 +03:00
/* v4l2_fh support */
spin_lock_init ( & vdev - > fh_lock ) ;
INIT_LIST_HEAD ( & vdev - > fh_list ) ;
2008-12-20 03:28:27 +03:00
/* Part 1: check device type */
2008-07-20 15:43:17 +04:00
switch ( type ) {
case VFL_TYPE_GRABBER :
name_base = " video " ;
break ;
case VFL_TYPE_VBI :
name_base = " vbi " ;
break ;
case VFL_TYPE_RADIO :
name_base = " radio " ;
break ;
2009-12-09 14:38:49 +03:00
case VFL_TYPE_SUBDEV :
name_base = " v4l-subdev " ;
break ;
2008-07-20 15:43:17 +04:00
default :
printk ( KERN_ERR " %s called with unknown type: %d \n " ,
__func__ , type ) ;
2008-09-03 23:47:39 +04:00
return - EINVAL ;
2008-07-20 15:43:17 +04:00
}
2008-12-20 03:28:27 +03:00
vdev - > vfl_type = type ;
vdev - > cdev = NULL ;
2010-05-16 16:24:06 +04:00
if ( vdev - > v4l2_dev ) {
if ( vdev - > v4l2_dev - > dev )
vdev - > parent = vdev - > v4l2_dev - > dev ;
if ( vdev - > ctrl_handler = = NULL )
vdev - > ctrl_handler = vdev - > v4l2_dev - > ctrl_handler ;
2011-03-22 16:14:07 +03:00
/* If the prio state pointer is NULL, then use the v4l2_device
prio state . */
if ( vdev - > prio = = NULL )
2011-02-24 16:42:24 +03:00
vdev - > prio = & vdev - > v4l2_dev - > prio ;
2010-05-16 16:24:06 +04:00
}
2008-10-04 15:36:54 +04:00
2009-09-06 14:13:14 +04:00
/* Part 2: find a free minor, device node number and device index. */
2008-10-04 15:36:54 +04:00
# ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* Keep the ranges for the first four types for historical
* reasons .
* Newer devices ( not yet in place ) should use the range
* of 128 - 191 and just pick the first free minor there
* ( new style ) . */
switch ( type ) {
case VFL_TYPE_GRABBER :
minor_offset = 0 ;
minor_cnt = 64 ;
break ;
case VFL_TYPE_RADIO :
minor_offset = 64 ;
minor_cnt = 64 ;
break ;
case VFL_TYPE_VBI :
minor_offset = 224 ;
minor_cnt = 32 ;
break ;
default :
minor_offset = 128 ;
minor_cnt = 64 ;
break ;
}
# endif
2009-09-06 14:13:14 +04:00
/* Pick a device node number */
2008-07-20 15:43:17 +04:00
mutex_lock ( & videodev_lock ) ;
2009-09-07 10:40:24 +04:00
nr = devnode_find ( vdev , nr = = - 1 ? 0 : nr , minor_cnt ) ;
2008-10-04 15:36:54 +04:00
if ( nr = = minor_cnt )
2009-09-07 10:40:24 +04:00
nr = devnode_find ( vdev , 0 , minor_cnt ) ;
2008-10-04 15:36:54 +04:00
if ( nr = = minor_cnt ) {
2009-09-06 14:13:14 +04:00
printk ( KERN_ERR " could not get a free device node number \n " ) ;
2008-10-04 15:36:54 +04:00
mutex_unlock ( & videodev_lock ) ;
return - ENFILE ;
2008-07-20 15:43:17 +04:00
}
2008-10-04 15:36:54 +04:00
# ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
2009-09-06 14:13:14 +04:00
/* 1-on-1 mapping of device node number to minor number */
2008-10-04 15:36:54 +04:00
i = nr ;
# else
2009-09-06 14:13:14 +04:00
/* The device node number and minor numbers are independent, so
we just find the first free minor number . */
2008-10-04 15:36:54 +04:00
for ( i = 0 ; i < VIDEO_NUM_DEVICES ; i + + )
if ( video_device [ i ] = = NULL )
break ;
if ( i = = VIDEO_NUM_DEVICES ) {
mutex_unlock ( & videodev_lock ) ;
printk ( KERN_ERR " could not get a free minor \n " ) ;
return - ENFILE ;
}
# endif
2008-12-20 03:28:27 +03:00
vdev - > minor = i + minor_offset ;
vdev - > num = nr ;
2009-09-07 10:40:24 +04:00
devnode_set ( vdev ) ;
2008-12-20 03:28:27 +03:00
/* Should not happen since we thought this minor was free */
WARN_ON ( video_device [ vdev - > minor ] ! = NULL ) ;
2009-06-19 18:32:56 +04:00
vdev - > index = get_index ( vdev ) ;
2008-07-20 15:43:17 +04:00
mutex_unlock ( & videodev_lock ) ;
2012-05-10 11:57:22 +04:00
/* if no lock was passed, then make sure the LOCK_ALL_FOPS bit is
clear and warn if it wasn ' t . */
if ( vdev - > lock = = NULL )
WARN_ON ( test_and_clear_bit ( V4L2_FL_LOCK_ALL_FOPS , & vdev - > flags ) ) ;
2008-07-20 15:43:17 +04:00
2012-05-10 12:36:00 +04:00
if ( vdev - > ioctl_ops )
determine_valid_ioctls ( vdev ) ;
2008-12-20 03:28:27 +03:00
/* Part 3: Initialize the character device */
vdev - > cdev = cdev_alloc ( ) ;
if ( vdev - > cdev = = NULL ) {
ret = - ENOMEM ;
goto cleanup ;
}
2010-07-04 02:15:09 +04:00
vdev - > cdev - > ops = & v4l2_fops ;
2009-12-09 14:38:49 +03:00
vdev - > cdev - > owner = owner ;
2008-12-20 03:28:27 +03:00
ret = cdev_add ( vdev - > cdev , MKDEV ( VIDEO_MAJOR , vdev - > minor ) , 1 ) ;
2008-08-30 00:31:35 +04:00
if ( ret < 0 ) {
printk ( KERN_ERR " %s: cdev_add failed \n " , __func__ ) ;
2008-12-20 03:28:27 +03:00
kfree ( vdev - > cdev ) ;
vdev - > cdev = NULL ;
goto cleanup ;
2008-08-30 00:31:35 +04:00
}
2008-12-20 03:28:27 +03:00
/* Part 4: register the device with sysfs */
vdev - > dev . class = & video_class ;
vdev - > dev . devt = MKDEV ( VIDEO_MAJOR , vdev - > minor ) ;
if ( vdev - > parent )
vdev - > dev . parent = vdev - > parent ;
2009-09-06 14:13:14 +04:00
dev_set_name ( & vdev - > dev , " %s%d " , name_base , vdev - > num ) ;
2008-12-20 03:28:27 +03:00
ret = device_register ( & vdev - > dev ) ;
2008-07-20 15:43:17 +04:00
if ( ret < 0 ) {
printk ( KERN_ERR " %s: device_register failed \n " , __func__ ) ;
2008-12-20 03:28:27 +03:00
goto cleanup ;
2008-07-20 15:43:17 +04:00
}
2008-12-20 03:28:27 +03:00
/* Register the release callback that will be called when the last
reference to the device goes away . */
vdev - > dev . release = v4l2_device_release ;
2008-07-20 15:43:17 +04:00
2009-09-06 14:54:00 +04:00
if ( nr ! = - 1 & & nr ! = vdev - > num & & warn_if_nr_in_use )
2009-11-27 19:56:50 +03:00
printk ( KERN_WARNING " %s: requested %s%d, got %s \n " , __func__ ,
name_base , nr , video_device_node_name ( vdev ) ) ;
2011-03-12 12:37:19 +03:00
/* Increase v4l2_device refcount */
if ( vdev - > v4l2_dev )
v4l2_device_get ( vdev - > v4l2_dev ) ;
2009-12-09 14:40:10 +03:00
# if defined(CONFIG_MEDIA_CONTROLLER)
/* Part 5: Register the entity. */
2011-04-08 16:04:06 +04:00
if ( vdev - > v4l2_dev & & vdev - > v4l2_dev - > mdev & &
vdev - > vfl_type ! = VFL_TYPE_SUBDEV ) {
2009-12-09 14:40:10 +03:00
vdev - > entity . type = MEDIA_ENT_T_DEVNODE_V4L ;
vdev - > entity . name = vdev - > name ;
2011-11-06 01:42:01 +04:00
vdev - > entity . info . v4l . major = VIDEO_MAJOR ;
vdev - > entity . info . v4l . minor = vdev - > minor ;
2009-12-09 14:40:10 +03:00
ret = media_device_register_entity ( vdev - > v4l2_dev - > mdev ,
& vdev - > entity ) ;
if ( ret < 0 )
printk ( KERN_WARNING
" %s: media_device_register_entity failed \n " ,
__func__ ) ;
}
# endif
/* Part 6: Activate this minor. The char device can now be used. */
2009-11-27 19:57:22 +03:00
set_bit ( V4L2_FL_REGISTERED , & vdev - > flags ) ;
2008-12-20 03:28:27 +03:00
mutex_lock ( & videodev_lock ) ;
video_device [ vdev - > minor ] = vdev ;
mutex_unlock ( & videodev_lock ) ;
2009-12-09 14:40:10 +03:00
2008-12-20 03:28:27 +03:00
return 0 ;
2008-08-30 00:31:35 +04:00
2008-12-20 03:28:27 +03:00
cleanup :
2008-07-20 15:43:17 +04:00
mutex_lock ( & videodev_lock ) ;
2008-12-20 03:28:27 +03:00
if ( vdev - > cdev )
cdev_del ( vdev - > cdev ) ;
2009-09-07 10:40:24 +04:00
devnode_clear ( vdev ) ;
2008-07-20 15:43:17 +04:00
mutex_unlock ( & videodev_lock ) ;
2008-12-20 03:28:27 +03:00
/* Mark this video device as never having been registered. */
vdev - > minor = - 1 ;
2008-07-20 15:43:17 +04:00
return ret ;
}
2009-12-09 14:38:49 +03:00
EXPORT_SYMBOL ( __video_register_device ) ;
2009-09-06 14:54:00 +04:00
2008-07-20 15:43:17 +04:00
/**
* video_unregister_device - unregister a video4linux device
2008-12-20 03:28:27 +03:00
* @ vdev : the device to unregister
2008-07-20 15:43:17 +04:00
*
2008-12-20 03:28:27 +03:00
* This unregisters the passed device . Future open calls will
* be met with errors .
2008-07-20 15:43:17 +04:00
*/
2008-12-20 03:28:27 +03:00
void video_unregister_device ( struct video_device * vdev )
2008-07-20 15:43:17 +04:00
{
2008-12-20 03:28:27 +03:00
/* Check if vdev was ever registered at all */
2009-11-27 19:57:22 +03:00
if ( ! vdev | | ! video_is_registered ( vdev ) )
2008-12-20 03:28:27 +03:00
return ;
2010-11-26 12:54:53 +03:00
mutex_lock ( & videodev_lock ) ;
/* This must be in a critical section to prevent a race with v4l2_open.
* Once this bit has been cleared video_get may never be called again .
*/
2009-11-27 19:57:22 +03:00
clear_bit ( V4L2_FL_REGISTERED , & vdev - > flags ) ;
2010-11-26 12:54:53 +03:00
mutex_unlock ( & videodev_lock ) ;
2008-12-20 03:28:27 +03:00
device_unregister ( & vdev - > dev ) ;
2008-07-20 15:43:17 +04:00
}
EXPORT_SYMBOL ( video_unregister_device ) ;
/*
* Initialise video for linux
*/
static int __init videodev_init ( void )
{
2008-08-30 00:31:35 +04:00
dev_t dev = MKDEV ( VIDEO_MAJOR , 0 ) ;
2008-07-20 15:43:17 +04:00
int ret ;
printk ( KERN_INFO " Linux video capture interface: v2.00 \n " ) ;
2008-08-30 00:31:35 +04:00
ret = register_chrdev_region ( dev , VIDEO_NUM_DEVICES , VIDEO_NAME ) ;
if ( ret < 0 ) {
printk ( KERN_WARNING " videodev: unable to get major %d \n " ,
VIDEO_MAJOR ) ;
return ret ;
2008-07-20 15:43:17 +04:00
}
ret = class_register ( & video_class ) ;
if ( ret < 0 ) {
2008-08-30 00:31:35 +04:00
unregister_chrdev_region ( dev , VIDEO_NUM_DEVICES ) ;
2008-07-20 15:43:17 +04:00
printk ( KERN_WARNING " video_dev: class_register failed \n " ) ;
return - EIO ;
}
return 0 ;
}
static void __exit videodev_exit ( void )
{
2008-08-30 00:31:35 +04:00
dev_t dev = MKDEV ( VIDEO_MAJOR , 0 ) ;
2008-07-20 15:43:17 +04:00
class_unregister ( & video_class ) ;
2008-08-30 00:31:35 +04:00
unregister_chrdev_region ( dev , VIDEO_NUM_DEVICES ) ;
2008-07-20 15:43:17 +04:00
}
2012-03-12 12:09:02 +04:00
subsys_initcall ( videodev_init ) ;
2008-07-20 15:43:17 +04:00
module_exit ( videodev_exit )
MODULE_AUTHOR ( " Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org> " ) ;
MODULE_DESCRIPTION ( " Device registrar for Video4Linux drivers v2 " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-03-02 21:40:57 +03:00
MODULE_ALIAS_CHARDEV_MAJOR ( VIDEO_MAJOR ) ;
2008-07-20 15:43:17 +04:00
/*
* Local variables :
* c - basic - offset : 8
* End :
*/