2009-12-09 14:38:49 +03:00
/*
2009-12-09 14:38:52 +03:00
* V4L2 sub - device
2009-12-09 14:38:49 +03:00
*
2009-12-09 14:38:52 +03:00
* Copyright ( C ) 2010 Nokia Corporation
2009-12-09 14:38:49 +03:00
*
2009-12-09 14:38:52 +03:00
* Contact : Laurent Pinchart < laurent . pinchart @ ideasonboard . com >
* Sakari Ailus < sakari . ailus @ iki . fi >
2009-12-09 14:38:49 +03:00
*
2009-12-09 14:38:52 +03:00
* 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 .
2009-12-09 14:38:49 +03:00
*
2009-12-09 14:38:52 +03:00
* 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 .
2009-12-09 14:38:49 +03:00
*
2009-12-09 14:38:52 +03:00
* 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
2009-12-09 14:38:49 +03:00
*/
# include <linux/ioctl.h>
2010-03-03 18:49:38 +03:00
# include <linux/slab.h>
# include <linux/types.h>
2009-12-09 14:38:49 +03:00
# include <linux/videodev2.h>
2011-08-01 23:26:38 +04:00
# include <linux/export.h>
2009-12-09 14:38:49 +03:00
2009-12-09 14:39:54 +03:00
# include <media/v4l2-ctrls.h>
2009-12-09 14:38:49 +03:00
# include <media/v4l2-device.h>
# include <media/v4l2-ioctl.h>
2010-03-03 18:49:38 +03:00
# include <media/v4l2-fh.h>
# include <media/v4l2-event.h>
2009-12-09 14:38:49 +03:00
2010-05-21 13:04:24 +04:00
static int subdev_fh_init ( struct v4l2_subdev_fh * fh , struct v4l2_subdev * sd )
{
# if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
2011-10-14 21:14:26 +04:00
fh - > pad = kzalloc ( sizeof ( * fh - > pad ) * sd - > entity . num_pads , GFP_KERNEL ) ;
if ( fh - > pad = = NULL )
2010-05-21 13:04:24 +04:00
return - ENOMEM ;
# endif
return 0 ;
}
static void subdev_fh_free ( struct v4l2_subdev_fh * fh )
{
# if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
2011-10-14 21:14:26 +04:00
kfree ( fh - > pad ) ;
fh - > pad = NULL ;
2010-05-21 13:04:24 +04:00
# endif
}
2009-12-09 14:38:49 +03:00
static int subdev_open ( struct file * file )
{
2010-03-03 18:49:38 +03:00
struct video_device * vdev = video_devdata ( file ) ;
struct v4l2_subdev * sd = vdev_to_v4l2_subdev ( vdev ) ;
2010-05-21 13:04:24 +04:00
struct v4l2_subdev_fh * subdev_fh ;
2009-12-09 14:40:08 +03:00
# if defined(CONFIG_MEDIA_CONTROLLER)
2010-08-02 02:05:09 +04:00
struct media_entity * entity = NULL ;
2009-12-09 14:40:08 +03:00
# endif
2010-03-03 18:49:38 +03:00
int ret ;
2010-05-21 13:04:24 +04:00
subdev_fh = kzalloc ( sizeof ( * subdev_fh ) , GFP_KERNEL ) ;
if ( subdev_fh = = NULL )
return - ENOMEM ;
2010-03-03 18:49:38 +03:00
2010-05-21 13:04:24 +04:00
ret = subdev_fh_init ( subdev_fh , sd ) ;
if ( ret ) {
kfree ( subdev_fh ) ;
return ret ;
}
2011-06-14 00:44:42 +04:00
v4l2_fh_init ( & subdev_fh - > vfh , vdev ) ;
2010-05-21 13:04:24 +04:00
v4l2_fh_add ( & subdev_fh - > vfh ) ;
file - > private_data = & subdev_fh - > vfh ;
2009-12-09 14:40:08 +03:00
# if defined(CONFIG_MEDIA_CONTROLLER)
if ( sd - > v4l2_dev - > mdev ) {
entity = media_entity_get ( & sd - > entity ) ;
if ( ! entity ) {
ret = - EBUSY ;
goto err ;
}
}
# endif
2010-05-21 13:04:24 +04:00
2010-08-02 02:05:09 +04:00
if ( sd - > internal_ops & & sd - > internal_ops - > open ) {
ret = sd - > internal_ops - > open ( sd , subdev_fh ) ;
if ( ret < 0 )
goto err ;
}
2009-12-09 14:38:49 +03:00
return 0 ;
2010-03-03 18:49:38 +03:00
err :
2010-08-02 02:05:09 +04:00
# if defined(CONFIG_MEDIA_CONTROLLER)
2015-02-03 17:27:38 +03:00
media_entity_put ( entity ) ;
2010-08-02 02:05:09 +04:00
# endif
2010-05-21 13:04:24 +04:00
v4l2_fh_del ( & subdev_fh - > vfh ) ;
v4l2_fh_exit ( & subdev_fh - > vfh ) ;
subdev_fh_free ( subdev_fh ) ;
kfree ( subdev_fh ) ;
2010-03-03 18:49:38 +03:00
return ret ;
2009-12-09 14:38:49 +03:00
}
static int subdev_close ( struct file * file )
{
2009-12-09 14:40:08 +03:00
struct video_device * vdev = video_devdata ( file ) ;
struct v4l2_subdev * sd = vdev_to_v4l2_subdev ( vdev ) ;
2010-03-03 18:49:38 +03:00
struct v4l2_fh * vfh = file - > private_data ;
2010-05-21 13:04:24 +04:00
struct v4l2_subdev_fh * subdev_fh = to_v4l2_subdev_fh ( vfh ) ;
2010-03-03 18:49:38 +03:00
2010-08-02 02:05:09 +04:00
if ( sd - > internal_ops & & sd - > internal_ops - > close )
sd - > internal_ops - > close ( sd , subdev_fh ) ;
2009-12-09 14:40:08 +03:00
# if defined(CONFIG_MEDIA_CONTROLLER)
if ( sd - > v4l2_dev - > mdev )
media_entity_put ( & sd - > entity ) ;
# endif
2010-05-21 13:04:24 +04:00
v4l2_fh_del ( vfh ) ;
v4l2_fh_exit ( vfh ) ;
subdev_fh_free ( subdev_fh ) ;
kfree ( subdev_fh ) ;
file - > private_data = NULL ;
2010-03-03 18:49:38 +03:00
2009-12-09 14:38:49 +03:00
return 0 ;
}
2014-07-22 08:40:00 +04:00
# if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
2014-06-04 15:22:03 +04:00
static int check_format ( struct v4l2_subdev * sd ,
struct v4l2_subdev_format * format )
{
if ( format - > which ! = V4L2_SUBDEV_FORMAT_TRY & &
format - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
if ( format - > pad > = sd - > entity . num_pads )
return - EINVAL ;
return 0 ;
}
static int check_crop ( struct v4l2_subdev * sd , struct v4l2_subdev_crop * crop )
{
if ( crop - > which ! = V4L2_SUBDEV_FORMAT_TRY & &
crop - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
if ( crop - > pad > = sd - > entity . num_pads )
return - EINVAL ;
return 0 ;
}
static int check_selection ( struct v4l2_subdev * sd ,
struct v4l2_subdev_selection * sel )
{
if ( sel - > which ! = V4L2_SUBDEV_FORMAT_TRY & &
sel - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
if ( sel - > pad > = sd - > entity . num_pads )
return - EINVAL ;
return 0 ;
}
static int check_edid ( struct v4l2_subdev * sd , struct v4l2_subdev_edid * edid )
{
if ( edid - > pad > = sd - > entity . num_pads )
return - EINVAL ;
if ( edid - > blocks & & edid - > edid = = NULL )
return - EINVAL ;
return 0 ;
}
2014-07-22 08:40:00 +04:00
# endif
2014-06-04 15:22:03 +04:00
2009-12-09 14:38:49 +03:00
static long subdev_do_ioctl ( struct file * file , unsigned int cmd , void * arg )
{
2009-12-09 14:39:54 +03:00
struct video_device * vdev = video_devdata ( file ) ;
struct v4l2_subdev * sd = vdev_to_v4l2_subdev ( vdev ) ;
2010-05-21 13:04:24 +04:00
struct v4l2_fh * vfh = file - > private_data ;
2010-03-16 02:26:04 +03:00
# if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
struct v4l2_subdev_fh * subdev_fh = to_v4l2_subdev_fh ( vfh ) ;
2014-06-04 15:22:03 +04:00
int rval ;
2014-07-22 08:40:00 +04:00
# endif
2009-12-09 14:39:54 +03:00
2009-12-09 14:38:49 +03:00
switch ( cmd ) {
2009-12-09 14:39:54 +03:00
case VIDIOC_QUERYCTRL :
2011-05-25 15:52:13 +04:00
return v4l2_queryctrl ( vfh - > ctrl_handler , arg ) ;
2009-12-09 14:39:54 +03:00
2014-06-10 11:22:06 +04:00
case VIDIOC_QUERY_EXT_CTRL :
return v4l2_query_ext_ctrl ( vfh - > ctrl_handler , arg ) ;
2009-12-09 14:39:54 +03:00
case VIDIOC_QUERYMENU :
2011-05-25 15:52:13 +04:00
return v4l2_querymenu ( vfh - > ctrl_handler , arg ) ;
2009-12-09 14:39:54 +03:00
case VIDIOC_G_CTRL :
2011-05-25 15:52:13 +04:00
return v4l2_g_ctrl ( vfh - > ctrl_handler , arg ) ;
2009-12-09 14:39:54 +03:00
case VIDIOC_S_CTRL :
2011-06-07 13:47:18 +04:00
return v4l2_s_ctrl ( vfh , vfh - > ctrl_handler , arg ) ;
2009-12-09 14:39:54 +03:00
case VIDIOC_G_EXT_CTRLS :
2011-05-25 15:52:13 +04:00
return v4l2_g_ext_ctrls ( vfh - > ctrl_handler , arg ) ;
2009-12-09 14:39:54 +03:00
case VIDIOC_S_EXT_CTRLS :
2011-06-07 13:47:18 +04:00
return v4l2_s_ext_ctrls ( vfh , vfh - > ctrl_handler , arg ) ;
2009-12-09 14:39:54 +03:00
case VIDIOC_TRY_EXT_CTRLS :
2011-05-25 15:52:13 +04:00
return v4l2_try_ext_ctrls ( vfh - > ctrl_handler , arg ) ;
2009-12-09 14:39:54 +03:00
2010-03-03 18:49:38 +03:00
case VIDIOC_DQEVENT :
if ( ! ( sd - > flags & V4L2_SUBDEV_FL_HAS_EVENTS ) )
return - ENOIOCTLCMD ;
2010-05-21 13:04:24 +04:00
return v4l2_event_dequeue ( vfh , arg , file - > f_flags & O_NONBLOCK ) ;
2010-03-03 18:49:38 +03:00
case VIDIOC_SUBSCRIBE_EVENT :
2010-05-21 13:04:24 +04:00
return v4l2_subdev_call ( sd , core , subscribe_event , vfh , arg ) ;
2010-03-03 18:49:38 +03:00
case VIDIOC_UNSUBSCRIBE_EVENT :
2010-05-21 13:04:24 +04:00
return v4l2_subdev_call ( sd , core , unsubscribe_event , vfh , arg ) ;
2011-09-19 09:04:56 +04:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
case VIDIOC_DBG_G_REGISTER :
{
struct v4l2_dbg_register * p = arg ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
return v4l2_subdev_call ( sd , core , g_register , p ) ;
}
case VIDIOC_DBG_S_REGISTER :
{
struct v4l2_dbg_register * p = arg ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
return v4l2_subdev_call ( sd , core , s_register , p ) ;
}
# endif
2011-10-01 18:13:59 +04:00
2012-02-02 15:26:20 +04:00
case VIDIOC_LOG_STATUS : {
int ret ;
pr_info ( " %s: ================= START STATUS ================= \n " ,
sd - > name ) ;
ret = v4l2_subdev_call ( sd , core , log_status ) ;
pr_info ( " %s: ================== END STATUS ================== \n " ,
sd - > name ) ;
return ret ;
}
2011-10-01 18:13:59 +04:00
2010-03-16 02:26:04 +03:00
# if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
case VIDIOC_SUBDEV_G_FMT : {
struct v4l2_subdev_format * format = arg ;
2014-06-04 15:22:03 +04:00
rval = check_format ( sd , format ) ;
if ( rval )
return rval ;
2010-03-16 02:26:04 +03:00
2015-03-04 12:47:54 +03:00
return v4l2_subdev_call ( sd , pad , get_fmt , subdev_fh - > pad , format ) ;
2010-03-16 02:26:04 +03:00
}
case VIDIOC_SUBDEV_S_FMT : {
struct v4l2_subdev_format * format = arg ;
2014-06-04 15:22:03 +04:00
rval = check_format ( sd , format ) ;
if ( rval )
return rval ;
2010-03-03 18:49:38 +03:00
2015-03-04 12:47:54 +03:00
return v4l2_subdev_call ( sd , pad , set_fmt , subdev_fh - > pad , format ) ;
2010-03-16 02:26:04 +03:00
}
2010-06-23 12:03:42 +04:00
case VIDIOC_SUBDEV_G_CROP : {
struct v4l2_subdev_crop * crop = arg ;
2011-11-14 22:30:24 +04:00
struct v4l2_subdev_selection sel ;
2010-06-23 12:03:42 +04:00
2014-06-04 15:22:03 +04:00
rval = check_crop ( sd , crop ) ;
if ( rval )
return rval ;
2010-06-23 12:03:42 +04:00
2011-11-14 22:30:24 +04:00
memset ( & sel , 0 , sizeof ( sel ) ) ;
sel . which = crop - > which ;
sel . pad = crop - > pad ;
2012-05-18 16:31:18 +04:00
sel . target = V4L2_SEL_TGT_CROP ;
2011-11-14 22:30:24 +04:00
rval = v4l2_subdev_call (
2015-03-04 12:47:54 +03:00
sd , pad , get_selection , subdev_fh - > pad , & sel ) ;
2011-11-14 22:30:24 +04:00
crop - > rect = sel . r ;
return rval ;
2010-06-23 12:03:42 +04:00
}
case VIDIOC_SUBDEV_S_CROP : {
struct v4l2_subdev_crop * crop = arg ;
2011-11-14 22:30:24 +04:00
struct v4l2_subdev_selection sel ;
2010-06-23 12:03:42 +04:00
2014-06-04 15:22:03 +04:00
rval = check_crop ( sd , crop ) ;
if ( rval )
return rval ;
2010-06-23 12:03:42 +04:00
2011-11-14 22:30:24 +04:00
memset ( & sel , 0 , sizeof ( sel ) ) ;
sel . which = crop - > which ;
sel . pad = crop - > pad ;
2012-05-18 16:31:18 +04:00
sel . target = V4L2_SEL_TGT_CROP ;
2011-11-14 22:30:24 +04:00
sel . r = crop - > rect ;
rval = v4l2_subdev_call (
2015-03-04 12:47:54 +03:00
sd , pad , set_selection , subdev_fh - > pad , & sel ) ;
2011-11-14 22:30:24 +04:00
crop - > rect = sel . r ;
return rval ;
2010-06-23 12:03:42 +04:00
}
2010-03-16 02:26:04 +03:00
case VIDIOC_SUBDEV_ENUM_MBUS_CODE : {
struct v4l2_subdev_mbus_code_enum * code = arg ;
2015-03-04 12:47:56 +03:00
if ( code - > which ! = V4L2_SUBDEV_FORMAT_TRY & &
code - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
2010-03-16 02:26:04 +03:00
if ( code - > pad > = sd - > entity . num_pads )
return - EINVAL ;
2015-03-04 12:47:54 +03:00
return v4l2_subdev_call ( sd , pad , enum_mbus_code , subdev_fh - > pad ,
2010-03-16 02:26:04 +03:00
code ) ;
}
case VIDIOC_SUBDEV_ENUM_FRAME_SIZE : {
struct v4l2_subdev_frame_size_enum * fse = arg ;
2015-03-04 12:47:56 +03:00
if ( fse - > which ! = V4L2_SUBDEV_FORMAT_TRY & &
fse - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
2010-03-16 02:26:04 +03:00
if ( fse - > pad > = sd - > entity . num_pads )
return - EINVAL ;
2015-03-04 12:47:54 +03:00
return v4l2_subdev_call ( sd , pad , enum_frame_size , subdev_fh - > pad ,
2010-03-16 02:26:04 +03:00
fse ) ;
}
2010-05-05 18:38:35 +04:00
2013-04-22 17:24:51 +04:00
case VIDIOC_SUBDEV_G_FRAME_INTERVAL : {
struct v4l2_subdev_frame_interval * fi = arg ;
if ( fi - > pad > = sd - > entity . num_pads )
return - EINVAL ;
2010-05-05 18:38:35 +04:00
return v4l2_subdev_call ( sd , video , g_frame_interval , arg ) ;
2013-04-22 17:24:51 +04:00
}
case VIDIOC_SUBDEV_S_FRAME_INTERVAL : {
struct v4l2_subdev_frame_interval * fi = arg ;
if ( fi - > pad > = sd - > entity . num_pads )
return - EINVAL ;
2010-05-05 18:38:35 +04:00
return v4l2_subdev_call ( sd , video , s_frame_interval , arg ) ;
2013-04-22 17:24:51 +04:00
}
2010-05-05 18:38:35 +04:00
case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL : {
struct v4l2_subdev_frame_interval_enum * fie = arg ;
2015-03-04 12:47:56 +03:00
if ( fie - > which ! = V4L2_SUBDEV_FORMAT_TRY & &
fie - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
2010-05-05 18:38:35 +04:00
if ( fie - > pad > = sd - > entity . num_pads )
return - EINVAL ;
2015-03-04 12:47:54 +03:00
return v4l2_subdev_call ( sd , pad , enum_frame_interval , subdev_fh - > pad ,
2010-05-05 18:38:35 +04:00
fie ) ;
}
2011-10-14 21:14:26 +04:00
case VIDIOC_SUBDEV_G_SELECTION : {
struct v4l2_subdev_selection * sel = arg ;
2014-06-04 15:22:03 +04:00
rval = check_selection ( sd , sel ) ;
if ( rval )
return rval ;
2011-10-14 21:14:26 +04:00
return v4l2_subdev_call (
2015-03-04 12:47:54 +03:00
sd , pad , get_selection , subdev_fh - > pad , sel ) ;
2011-10-14 21:14:26 +04:00
}
case VIDIOC_SUBDEV_S_SELECTION : {
struct v4l2_subdev_selection * sel = arg ;
2014-06-04 15:22:03 +04:00
rval = check_selection ( sd , sel ) ;
if ( rval )
return rval ;
2011-10-14 21:14:26 +04:00
return v4l2_subdev_call (
2015-03-04 12:47:54 +03:00
sd , pad , set_selection , subdev_fh - > pad , sel ) ;
2011-10-14 21:14:26 +04:00
}
2012-08-10 13:07:12 +04:00
2014-01-29 17:07:13 +04:00
case VIDIOC_G_EDID : {
struct v4l2_subdev_edid * edid = arg ;
2012-08-10 13:07:12 +04:00
2014-06-04 15:22:03 +04:00
rval = check_edid ( sd , edid ) ;
if ( rval )
return rval ;
2014-01-29 17:07:13 +04:00
return v4l2_subdev_call ( sd , pad , get_edid , edid ) ;
}
case VIDIOC_S_EDID : {
struct v4l2_subdev_edid * edid = arg ;
2014-06-04 15:22:03 +04:00
rval = check_edid ( sd , edid ) ;
if ( rval )
return rval ;
2014-01-29 17:07:13 +04:00
return v4l2_subdev_call ( sd , pad , set_edid , edid ) ;
}
2014-01-29 17:07:13 +04:00
case VIDIOC_SUBDEV_DV_TIMINGS_CAP : {
struct v4l2_dv_timings_cap * cap = arg ;
if ( cap - > pad > = sd - > entity . num_pads )
return - EINVAL ;
return v4l2_subdev_call ( sd , pad , dv_timings_cap , cap ) ;
}
case VIDIOC_SUBDEV_ENUM_DV_TIMINGS : {
struct v4l2_enum_dv_timings * dvt = arg ;
if ( dvt - > pad > = sd - > entity . num_pads )
return - EINVAL ;
return v4l2_subdev_call ( sd , pad , enum_dv_timings , dvt ) ;
}
case VIDIOC_SUBDEV_QUERY_DV_TIMINGS :
return v4l2_subdev_call ( sd , video , query_dv_timings , arg ) ;
case VIDIOC_SUBDEV_G_DV_TIMINGS :
return v4l2_subdev_call ( sd , video , g_dv_timings , arg ) ;
case VIDIOC_SUBDEV_S_DV_TIMINGS :
return v4l2_subdev_call ( sd , video , s_dv_timings , arg ) ;
2010-03-16 02:26:04 +03:00
# endif
2009-12-09 14:38:49 +03:00
default :
2010-02-26 18:23:10 +03:00
return v4l2_subdev_call ( sd , core , ioctl , cmd , arg ) ;
2009-12-09 14:38:49 +03:00
}
return 0 ;
}
static long subdev_ioctl ( struct file * file , unsigned int cmd ,
unsigned long arg )
{
return video_usercopy ( file , cmd , arg , subdev_do_ioctl ) ;
}
2014-02-10 15:08:44 +04:00
# ifdef CONFIG_COMPAT
static long subdev_compat_ioctl32 ( struct file * file , unsigned int cmd ,
unsigned long arg )
{
struct video_device * vdev = video_devdata ( file ) ;
struct v4l2_subdev * sd = vdev_to_v4l2_subdev ( vdev ) ;
return v4l2_subdev_call ( sd , core , compat_ioctl32 , cmd , arg ) ;
}
# endif
2010-03-03 18:49:38 +03:00
static unsigned int subdev_poll ( struct file * file , poll_table * wait )
{
struct video_device * vdev = video_devdata ( file ) ;
struct v4l2_subdev * sd = vdev_to_v4l2_subdev ( vdev ) ;
struct v4l2_fh * fh = file - > private_data ;
if ( ! ( sd - > flags & V4L2_SUBDEV_FL_HAS_EVENTS ) )
return POLLERR ;
2011-06-14 00:44:42 +04:00
poll_wait ( file , & fh - > wait , wait ) ;
2010-03-03 18:49:38 +03:00
if ( v4l2_event_pending ( fh ) )
return POLLPRI ;
return 0 ;
}
2009-12-09 14:38:49 +03:00
const struct v4l2_file_operations v4l2_subdev_fops = {
. owner = THIS_MODULE ,
. open = subdev_open ,
. unlocked_ioctl = subdev_ioctl ,
2014-02-10 15:08:44 +04:00
# ifdef CONFIG_COMPAT
. compat_ioctl32 = subdev_compat_ioctl32 ,
# endif
2009-12-09 14:38:49 +03:00
. release = subdev_close ,
2010-03-03 18:49:38 +03:00
. poll = subdev_poll ,
2009-12-09 14:38:49 +03:00
} ;
2009-12-09 14:38:52 +03:00
2011-10-11 00:01:25 +04:00
# ifdef CONFIG_MEDIA_CONTROLLER
int v4l2_subdev_link_validate_default ( struct v4l2_subdev * sd ,
struct media_link * link ,
struct v4l2_subdev_format * source_fmt ,
struct v4l2_subdev_format * sink_fmt )
{
2014-05-19 18:36:23 +04:00
/* The width, height and code must match. */
2011-10-11 00:01:25 +04:00
if ( source_fmt - > format . width ! = sink_fmt - > format . width
| | source_fmt - > format . height ! = sink_fmt - > format . height
| | source_fmt - > format . code ! = sink_fmt - > format . code )
return - EINVAL ;
2014-05-19 18:36:23 +04:00
/* The field order must match, or the sink field order must be NONE
* to support interlaced hardware connected to bridges that support
* progressive formats only .
*/
if ( source_fmt - > format . field ! = sink_fmt - > format . field & &
sink_fmt - > format . field ! = V4L2_FIELD_NONE )
return - EINVAL ;
2011-10-11 00:01:25 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( v4l2_subdev_link_validate_default ) ;
static int
v4l2_subdev_link_validate_get_format ( struct media_pad * pad ,
struct v4l2_subdev_format * fmt )
{
2012-10-21 00:47:22 +04:00
if ( media_entity_type ( pad - > entity ) = = MEDIA_ENT_T_V4L2_SUBDEV ) {
struct v4l2_subdev * sd =
media_entity_to_v4l2_subdev ( pad - > entity ) ;
2011-10-11 00:01:25 +04:00
fmt - > which = V4L2_SUBDEV_FORMAT_ACTIVE ;
fmt - > pad = pad - > index ;
2012-10-21 00:47:22 +04:00
return v4l2_subdev_call ( sd , pad , get_fmt , NULL , fmt ) ;
2011-10-11 00:01:25 +04:00
}
2012-10-21 00:47:22 +04:00
WARN ( pad - > entity - > type ! = MEDIA_ENT_T_DEVNODE_V4L ,
" Driver bug! Wrong media entity type 0x%08x, entity %s \n " ,
pad - > entity - > type , pad - > entity - > name ) ;
return - EINVAL ;
2011-10-11 00:01:25 +04:00
}
int v4l2_subdev_link_validate ( struct media_link * link )
{
struct v4l2_subdev * sink ;
struct v4l2_subdev_format sink_fmt , source_fmt ;
int rval ;
rval = v4l2_subdev_link_validate_get_format (
link - > source , & source_fmt ) ;
if ( rval < 0 )
return 0 ;
rval = v4l2_subdev_link_validate_get_format (
link - > sink , & sink_fmt ) ;
if ( rval < 0 )
return 0 ;
sink = media_entity_to_v4l2_subdev ( link - > sink - > entity ) ;
rval = v4l2_subdev_call ( sink , pad , link_validate , link ,
& source_fmt , & sink_fmt ) ;
if ( rval ! = - ENOIOCTLCMD )
return rval ;
return v4l2_subdev_link_validate_default (
sink , link , & source_fmt , & sink_fmt ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_subdev_link_validate ) ;
# endif /* CONFIG_MEDIA_CONTROLLER */
2009-12-09 14:38:52 +03:00
void v4l2_subdev_init ( struct v4l2_subdev * sd , const struct v4l2_subdev_ops * ops )
{
INIT_LIST_HEAD ( & sd - > list ) ;
BUG_ON ( ! ops ) ;
sd - > ops = ops ;
sd - > v4l2_dev = NULL ;
sd - > flags = 0 ;
sd - > name [ 0 ] = ' \0 ' ;
sd - > grp_id = 0 ;
sd - > dev_priv = NULL ;
sd - > host_priv = NULL ;
2009-12-09 14:40:08 +03:00
# if defined(CONFIG_MEDIA_CONTROLLER)
sd - > entity . name = sd - > name ;
sd - > entity . type = MEDIA_ENT_T_V4L2_SUBDEV ;
# endif
2009-12-09 14:38:52 +03:00
}
EXPORT_SYMBOL ( v4l2_subdev_init ) ;