2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-10-07 17:06:16 +04:00
/*
2011-04-28 16:06:19 +04:00
* Samsung S5P / EXYNOS4 SoC series camera interface ( camera capture ) driver
2010-10-07 17:06:16 +04:00
*
2012-04-25 13:55:42 +04:00
* Copyright ( C ) 2010 - 2012 Samsung Electronics Co . , Ltd .
* Sylwester Nawrocki < s . nawrocki @ samsung . com >
2010-10-07 17:06:16 +04:00
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/bug.h>
# include <linux/interrupt.h>
# include <linux/device.h>
2011-09-02 13:25:32 +04:00
# include <linux/pm_runtime.h>
2010-10-07 17:06:16 +04:00
# include <linux/list.h>
# include <linux/slab.h>
# include <linux/videodev2.h>
# include <media/v4l2-device.h>
# include <media/v4l2-ioctl.h>
# include <media/v4l2-mem2mem.h>
2020-05-28 16:26:05 +03:00
# include <media/v4l2-rect.h>
2015-09-22 16:30:29 +03:00
# include <media/videobuf2-v4l2.h>
2010-12-01 16:14:59 +03:00
# include <media/videobuf2-dma-contig.h>
2010-10-07 17:06:16 +04:00
2013-05-31 18:37:19 +04:00
# include "common.h"
2010-10-07 17:06:16 +04:00
# include "fimc-core.h"
2012-05-02 13:14:49 +04:00
# include "fimc-reg.h"
2013-05-31 18:37:19 +04:00
# include "media-dev.h"
2010-10-07 17:06:16 +04:00
2012-04-27 16:33:23 +04:00
static int fimc_capture_hw_init ( struct fimc_dev * fimc )
2011-06-10 22:36:53 +04:00
{
2013-03-20 17:44:39 +04:00
struct fimc_source_info * si = & fimc - > vid_cap . source_config ;
2011-06-10 22:36:53 +04:00
struct fimc_ctx * ctx = fimc - > vid_cap . ctx ;
2013-03-20 17:44:39 +04:00
int ret ;
2011-06-10 22:36:53 +04:00
unsigned long flags ;
2013-03-20 17:44:39 +04:00
if ( ctx = = NULL | | ctx - > s_frame . fmt = = NULL )
2011-06-10 22:36:53 +04:00
return - EINVAL ;
2013-03-20 17:44:39 +04:00
if ( si - > fimc_bus_type = = FIMC_BUS_TYPE_ISP_WRITEBACK ) {
ret = fimc_hw_camblk_cfg_writeback ( fimc ) ;
if ( ret < 0 )
return ret ;
}
2011-06-10 22:36:53 +04:00
spin_lock_irqsave ( & fimc - > slock , flags ) ;
fimc_prepare_dma_offset ( ctx , & ctx - > d_frame ) ;
fimc_set_yuv_order ( ctx ) ;
2013-03-20 17:44:39 +04:00
fimc_hw_set_camera_polarity ( fimc , si ) ;
fimc_hw_set_camera_type ( fimc , si ) ;
fimc_hw_set_camera_source ( fimc , si ) ;
2011-06-10 22:36:53 +04:00
fimc_hw_set_camera_offset ( fimc , & ctx - > s_frame ) ;
ret = fimc_set_scaler_info ( ctx ) ;
if ( ! ret ) {
fimc_hw_set_input_path ( ctx ) ;
fimc_hw_set_prescaler ( ctx ) ;
fimc_hw_set_mainscaler ( ctx ) ;
fimc_hw_set_target_format ( ctx ) ;
fimc_hw_set_rotation ( ctx ) ;
2012-04-02 13:41:22 +04:00
fimc_hw_set_effect ( ctx ) ;
2011-06-10 22:36:53 +04:00
fimc_hw_set_output_path ( ctx ) ;
fimc_hw_set_out_dma ( ctx ) ;
2013-03-26 15:22:21 +04:00
if ( fimc - > drv_data - > alpha_color )
2011-12-01 21:02:24 +04:00
fimc_hw_set_rgb_alpha ( ctx ) ;
2011-08-25 03:35:30 +04:00
clear_bit ( ST_CAPT_APPLY_CFG , & fimc - > state ) ;
2011-06-10 22:36:53 +04:00
}
spin_unlock_irqrestore ( & fimc - > slock , flags ) ;
return ret ;
}
2012-04-27 16:33:23 +04:00
/*
* Reinitialize the driver so it is ready to start the streaming again .
* Set fimc - > state to indicate stream off and the hardware shut down state .
* If not suspending ( @ suspend is false ) , return any buffers to videobuf2 .
* Otherwise put any owned buffers onto the pending buffers queue , so they
* can be re - spun when the device is being resumed . Also perform FIMC
* software reset and disable streaming on the whole pipeline if required .
*/
2011-08-25 03:45:34 +04:00
static int fimc_capture_state_cleanup ( struct fimc_dev * fimc , bool suspend )
2010-10-07 17:06:16 +04:00
{
2011-08-29 15:51:49 +04:00
struct fimc_vid_cap * cap = & fimc - > vid_cap ;
2010-12-01 16:14:59 +03:00
struct fimc_vid_buffer * buf ;
2011-08-29 15:51:49 +04:00
unsigned long flags ;
2011-08-25 03:45:34 +04:00
bool streaming ;
2010-10-07 17:06:16 +04:00
spin_lock_irqsave ( & fimc - > slock , flags ) ;
2011-08-25 03:45:34 +04:00
streaming = fimc - > state & ( 1 < < ST_CAPT_ISP_STREAM ) ;
2010-10-07 17:06:16 +04:00
2011-08-25 03:45:34 +04:00
fimc - > state & = ~ ( 1 < < ST_CAPT_RUN | 1 < < ST_CAPT_SHUT |
1 < < ST_CAPT_STREAM | 1 < < ST_CAPT_ISP_STREAM ) ;
2012-03-16 18:47:51 +04:00
if ( suspend )
fimc - > state | = ( 1 < < ST_CAPT_SUSPENDED ) ;
else
2011-08-25 03:45:34 +04:00
fimc - > state & = ~ ( 1 < < ST_CAPT_PEND | 1 < < ST_CAPT_SUSPENDED ) ;
2010-12-01 16:14:59 +03:00
2011-08-25 03:45:34 +04:00
/* Release unused buffers */
while ( ! suspend & & ! list_empty ( & cap - > pending_buf_q ) ) {
2011-06-10 22:36:59 +04:00
buf = fimc_pending_queue_pop ( cap ) ;
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
vb2_buffer_done ( & buf - > vb . vb2_buf , VB2_BUF_STATE_ERROR ) ;
2010-12-01 16:14:59 +03:00
}
2011-08-25 03:45:34 +04:00
/* If suspending put unused buffers onto pending queue */
2010-12-01 16:14:59 +03:00
while ( ! list_empty ( & cap - > active_buf_q ) ) {
2011-06-10 22:36:59 +04:00
buf = fimc_active_queue_pop ( cap ) ;
2011-08-25 03:45:34 +04:00
if ( suspend )
fimc_pending_queue_add ( cap , buf ) ;
else
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
vb2_buffer_done ( & buf - > vb . vb2_buf , VB2_BUF_STATE_ERROR ) ;
2010-12-01 16:14:59 +03:00
}
2011-10-05 21:20:45 +04:00
fimc_hw_reset ( fimc ) ;
cap - > buf_index = 0 ;
2010-10-07 17:06:16 +04:00
spin_unlock_irqrestore ( & fimc - > slock , flags ) ;
2011-08-26 21:51:00 +04:00
2011-08-25 03:45:34 +04:00
if ( streaming )
2013-05-31 18:37:22 +04:00
return fimc_pipeline_call ( & cap - > ve , set_stream , 0 ) ;
2011-08-26 21:51:00 +04:00
else
return 0 ;
2011-08-29 15:51:49 +04:00
}
2011-08-25 03:45:34 +04:00
static int fimc_stop_capture ( struct fimc_dev * fimc , bool suspend )
2011-08-29 15:51:49 +04:00
{
unsigned long flags ;
if ( ! fimc_capture_active ( fimc ) )
return 0 ;
spin_lock_irqsave ( & fimc - > slock , flags ) ;
set_bit ( ST_CAPT_SHUT , & fimc - > state ) ;
fimc_deactivate_capture ( fimc ) ;
spin_unlock_irqrestore ( & fimc - > slock , flags ) ;
wait_event_timeout ( fimc - > irq_queue ,
! test_bit ( ST_CAPT_SHUT , & fimc - > state ) ,
2011-08-25 03:45:34 +04:00
( 2 * HZ / 10 ) ) ; /* 200 ms */
2010-10-07 17:06:16 +04:00
2011-08-25 03:45:34 +04:00
return fimc_capture_state_cleanup ( fimc , suspend ) ;
2010-10-07 17:06:16 +04:00
}
2011-08-25 03:35:30 +04:00
/**
* fimc_capture_config_update - apply the camera interface configuration
2017-11-29 12:32:51 +03:00
* @ ctx : FIMC capture context
2011-08-25 03:35:30 +04:00
*
* To be called from within the interrupt handler with fimc . slock
* spinlock held . It updates the camera pixel crop , rotation and
* image flip in H / W .
*/
2012-05-08 22:51:24 +04:00
static int fimc_capture_config_update ( struct fimc_ctx * ctx )
2011-08-25 03:35:30 +04:00
{
struct fimc_dev * fimc = ctx - > fimc_dev ;
int ret ;
fimc_hw_set_camera_offset ( fimc , & ctx - > s_frame ) ;
2012-03-19 20:11:40 +04:00
2011-08-25 03:35:30 +04:00
ret = fimc_set_scaler_info ( ctx ) ;
2012-03-19 20:11:40 +04:00
if ( ret )
return ret ;
fimc_hw_set_prescaler ( ctx ) ;
fimc_hw_set_mainscaler ( ctx ) ;
fimc_hw_set_target_format ( ctx ) ;
fimc_hw_set_rotation ( ctx ) ;
2012-04-02 13:41:22 +04:00
fimc_hw_set_effect ( ctx ) ;
2012-03-19 20:11:40 +04:00
fimc_prepare_dma_offset ( ctx , & ctx - > d_frame ) ;
fimc_hw_set_out_dma ( ctx ) ;
2013-03-26 15:22:21 +04:00
if ( fimc - > drv_data - > alpha_color )
2012-03-19 20:11:40 +04:00
fimc_hw_set_rgb_alpha ( ctx ) ;
clear_bit ( ST_CAPT_APPLY_CFG , & fimc - > state ) ;
2011-08-25 03:35:30 +04:00
return ret ;
}
2011-08-29 15:51:49 +04:00
2012-05-08 22:51:24 +04:00
void fimc_capture_irq_handler ( struct fimc_dev * fimc , int deq_buf )
{
struct fimc_vid_cap * cap = & fimc - > vid_cap ;
2013-05-31 18:37:22 +04:00
struct fimc_pipeline * p = to_fimc_pipeline ( cap - > ve . pipe ) ;
struct v4l2_subdev * csis = p - > subdevs [ IDX_CSIS ] ;
2012-09-24 18:08:45 +04:00
struct fimc_frame * f = & cap - > ctx - > d_frame ;
2012-05-08 22:51:24 +04:00
struct fimc_vid_buffer * v_buf ;
if ( test_and_clear_bit ( ST_CAPT_SHUT , & fimc - > state ) ) {
wake_up ( & fimc - > irq_queue ) ;
goto done ;
}
if ( ! list_empty ( & cap - > active_buf_q ) & &
test_bit ( ST_CAPT_RUN , & fimc - > state ) & & deq_buf ) {
v_buf = fimc_active_queue_pop ( cap ) ;
2015-11-03 13:16:37 +03:00
v_buf - > vb . vb2_buf . timestamp = ktime_get_ns ( ) ;
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
v_buf - > vb . sequence = cap - > frame_count + + ;
2012-05-08 22:51:24 +04:00
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
vb2_buffer_done ( & v_buf - > vb . vb2_buf , VB2_BUF_STATE_DONE ) ;
2012-05-08 22:51:24 +04:00
}
if ( ! list_empty ( & cap - > pending_buf_q ) ) {
v_buf = fimc_pending_queue_pop ( cap ) ;
2020-11-24 11:41:28 +03:00
fimc_hw_set_output_addr ( fimc , & v_buf - > addr , cap - > buf_index ) ;
2012-05-08 22:51:24 +04:00
v_buf - > index = cap - > buf_index ;
/* Move the buffer to the capture active queue */
fimc_active_queue_add ( cap , v_buf ) ;
dbg ( " next frame: %d, done frame: %d " ,
fimc_hw_get_frame_index ( fimc ) , v_buf - > index ) ;
if ( + + cap - > buf_index > = FIMC_MAX_OUT_BUFS )
cap - > buf_index = 0 ;
}
2012-09-24 18:08:45 +04:00
/*
* Set up a buffer at MIPI - CSIS if current image format
* requires the frame embedded data capture .
*/
if ( f - > fmt - > mdataplanes & & ! list_empty ( & cap - > active_buf_q ) ) {
unsigned int plane = ffs ( f - > fmt - > mdataplanes ) - 1 ;
unsigned int size = f - > payload [ plane ] ;
s32 index = fimc_hw_get_frame_index ( fimc ) ;
void * vaddr ;
list_for_each_entry ( v_buf , & cap - > active_buf_q , list ) {
if ( v_buf - > index ! = index )
continue ;
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
vaddr = vb2_plane_vaddr ( & v_buf - > vb . vb2_buf , plane ) ;
2012-09-24 18:08:45 +04:00
v4l2_subdev_call ( csis , video , s_rx_buffer ,
vaddr , & size ) ;
break ;
}
}
2012-05-08 22:51:24 +04:00
if ( cap - > active_buf_cnt = = 0 ) {
if ( deq_buf )
clear_bit ( ST_CAPT_RUN , & fimc - > state ) ;
if ( + + cap - > buf_index > = FIMC_MAX_OUT_BUFS )
cap - > buf_index = 0 ;
} else {
set_bit ( ST_CAPT_RUN , & fimc - > state ) ;
}
2012-04-27 16:33:23 +04:00
if ( test_bit ( ST_CAPT_APPLY_CFG , & fimc - > state ) )
fimc_capture_config_update ( cap - > ctx ) ;
2012-05-08 22:51:24 +04:00
done :
if ( cap - > active_buf_cnt = = 1 ) {
fimc_deactivate_capture ( fimc ) ;
clear_bit ( ST_CAPT_STREAM , & fimc - > state ) ;
}
dbg ( " frame: %d, active_buf_cnt: %d " ,
fimc_hw_get_frame_index ( fimc ) , cap - > active_buf_cnt ) ;
}
2011-08-29 15:51:49 +04:00
static int start_streaming ( struct vb2_queue * q , unsigned int count )
2010-12-01 16:14:59 +03:00
{
struct fimc_ctx * ctx = q - > drv_priv ;
struct fimc_dev * fimc = ctx - > fimc_dev ;
2011-06-10 22:36:53 +04:00
struct fimc_vid_cap * vid_cap = & fimc - > vid_cap ;
2011-08-29 15:51:49 +04:00
int min_bufs ;
2010-12-01 16:14:59 +03:00
int ret ;
2011-06-10 22:36:53 +04:00
vid_cap - > frame_count = 0 ;
2011-02-07 21:59:46 +03:00
2012-04-27 16:33:23 +04:00
ret = fimc_capture_hw_init ( fimc ) ;
if ( ret ) {
fimc_capture_state_cleanup ( fimc , false ) ;
return ret ;
}
2010-12-01 16:14:59 +03:00
set_bit ( ST_CAPT_PEND , & fimc - > state ) ;
2011-08-29 15:51:49 +04:00
min_bufs = fimc - > vid_cap . reqbufs_count > 1 ? 2 : 1 ;
2011-08-26 21:51:00 +04:00
if ( vid_cap - > active_buf_cnt > = min_bufs & &
! test_and_set_bit ( ST_CAPT_STREAM , & fimc - > state ) ) {
2011-08-29 15:51:49 +04:00
fimc_activate_capture ( ctx ) ;
2011-08-26 21:51:00 +04:00
if ( ! test_and_set_bit ( ST_CAPT_ISP_STREAM , & fimc - > state ) )
2013-05-31 18:37:22 +04:00
return fimc_pipeline_call ( & vid_cap - > ve , set_stream , 1 ) ;
2011-08-26 21:51:00 +04:00
}
2010-12-01 16:14:59 +03:00
return 0 ;
}
2014-04-17 09:47:21 +04:00
static void stop_streaming ( struct vb2_queue * q )
2010-12-01 16:14:59 +03:00
{
struct fimc_ctx * ctx = q - > drv_priv ;
struct fimc_dev * fimc = ctx - > fimc_dev ;
2011-02-23 14:24:33 +03:00
if ( ! fimc_capture_active ( fimc ) )
2014-04-17 09:47:21 +04:00
return ;
2010-12-01 16:14:59 +03:00
2014-04-17 09:47:21 +04:00
fimc_stop_capture ( fimc , false ) ;
2010-12-01 16:14:59 +03:00
}
2011-09-02 13:25:32 +04:00
int fimc_capture_suspend ( struct fimc_dev * fimc )
{
2011-08-25 03:45:34 +04:00
bool suspend = fimc_capture_busy ( fimc ) ;
int ret = fimc_stop_capture ( fimc , suspend ) ;
if ( ret )
return ret ;
2013-05-31 18:37:22 +04:00
return fimc_pipeline_call ( & fimc - > vid_cap . ve , close ) ;
2011-09-02 13:25:32 +04:00
}
2011-08-25 03:45:34 +04:00
static void buffer_queue ( struct vb2_buffer * vb ) ;
2011-09-02 13:25:32 +04:00
int fimc_capture_resume ( struct fimc_dev * fimc )
{
2011-08-25 03:45:34 +04:00
struct fimc_vid_cap * vid_cap = & fimc - > vid_cap ;
2013-05-31 18:37:18 +04:00
struct exynos_video_entity * ve = & vid_cap - > ve ;
2011-08-25 03:45:34 +04:00
struct fimc_vid_buffer * buf ;
int i ;
if ( ! test_and_clear_bit ( ST_CAPT_SUSPENDED , & fimc - > state ) )
return 0 ;
INIT_LIST_HEAD ( & fimc - > vid_cap . active_buf_q ) ;
vid_cap - > buf_index = 0 ;
2013-05-31 18:37:22 +04:00
fimc_pipeline_call ( ve , open , & ve - > vdev . entity , false ) ;
2012-04-27 16:33:23 +04:00
fimc_capture_hw_init ( fimc ) ;
2011-08-25 03:45:34 +04:00
clear_bit ( ST_CAPT_SUSPENDED , & fimc - > state ) ;
for ( i = 0 ; i < vid_cap - > reqbufs_count ; i + + ) {
if ( list_empty ( & vid_cap - > pending_buf_q ) )
break ;
buf = fimc_pending_queue_pop ( vid_cap ) ;
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
buffer_queue ( & buf - > vb . vb2_buf ) ;
2011-08-25 03:45:34 +04:00
}
2011-09-02 13:25:32 +04:00
return 0 ;
2011-08-25 03:45:34 +04:00
2011-09-02 13:25:32 +04:00
}
2015-10-28 05:50:37 +03:00
static int queue_setup ( struct vb2_queue * vq ,
2011-08-24 17:30:21 +04:00
unsigned int * num_buffers , unsigned int * num_planes ,
2016-04-15 15:15:05 +03:00
unsigned int sizes [ ] , struct device * alloc_devs [ ] )
2010-12-01 16:14:59 +03:00
{
struct fimc_ctx * ctx = vq - > drv_priv ;
2012-04-23 00:07:09 +04:00
struct fimc_frame * frame = & ctx - > d_frame ;
struct fimc_fmt * fmt = frame - > fmt ;
2015-10-28 05:50:37 +03:00
unsigned long wh = frame - > f_width * frame - > f_height ;
2010-12-08 20:05:08 +03:00
int i ;
2010-12-01 16:14:59 +03:00
2012-04-23 00:07:09 +04:00
if ( fmt = = NULL )
2010-12-01 16:14:59 +03:00
return - EINVAL ;
2015-10-28 05:50:37 +03:00
if ( * num_planes ) {
if ( * num_planes ! = fmt - > memplanes )
return - EINVAL ;
2016-02-16 12:30:19 +03:00
for ( i = 0 ; i < * num_planes ; i + + )
2015-10-28 05:50:37 +03:00
if ( sizes [ i ] < ( wh * fmt - > depth [ i ] ) / 8 )
return - EINVAL ;
return 0 ;
}
2010-12-08 20:05:08 +03:00
* num_planes = fmt - > memplanes ;
2010-12-01 16:14:59 +03:00
2010-12-08 20:05:08 +03:00
for ( i = 0 ; i < fmt - > memplanes ; i + + ) {
2012-04-23 00:07:09 +04:00
unsigned int size = ( wh * fmt - > depth [ i ] ) / 8 ;
2015-10-28 05:50:37 +03:00
if ( fimc_fmt_is_user_defined ( fmt - > color ) )
2012-09-24 18:08:45 +04:00
sizes [ i ] = frame - > payload [ i ] ;
2012-04-23 00:07:09 +04:00
else
2012-05-16 22:00:26 +04:00
sizes [ i ] = max_t ( u32 , size , frame - > payload [ i ] ) ;
2010-12-08 20:05:08 +03:00
}
2010-12-01 16:14:59 +03:00
2010-12-08 20:05:08 +03:00
return 0 ;
2010-12-01 16:14:59 +03:00
}
static int buffer_prepare ( struct vb2_buffer * vb )
{
struct vb2_queue * vq = vb - > vb2_queue ;
struct fimc_ctx * ctx = vq - > drv_priv ;
int i ;
2011-08-26 21:51:00 +04:00
if ( ctx - > d_frame . fmt = = NULL )
2010-12-08 20:05:08 +03:00
return - EINVAL ;
2010-12-01 16:14:59 +03:00
2010-12-08 20:05:08 +03:00
for ( i = 0 ; i < ctx - > d_frame . fmt - > memplanes ; i + + ) {
2011-08-26 21:51:00 +04:00
unsigned long size = ctx - > d_frame . payload [ i ] ;
2010-12-01 16:14:59 +03:00
if ( vb2_plane_size ( vb , i ) < size ) {
2013-05-31 18:37:18 +04:00
v4l2_err ( & ctx - > fimc_dev - > vid_cap . ve . vdev ,
2011-06-10 22:36:48 +04:00
" User buffer too small (%ld < %ld) \n " ,
2010-12-01 16:14:59 +03:00
vb2_plane_size ( vb , i ) , size ) ;
return - EINVAL ;
}
vb2_set_plane_payload ( vb , i , size ) ;
}
return 0 ;
}
static void buffer_queue ( struct vb2_buffer * vb )
{
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
struct vb2_v4l2_buffer * vbuf = to_vb2_v4l2_buffer ( vb ) ;
2010-12-01 16:14:59 +03:00
struct fimc_vid_buffer * buf
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
= container_of ( vbuf , struct fimc_vid_buffer , vb ) ;
2011-08-26 21:51:00 +04:00
struct fimc_ctx * ctx = vb2_get_drv_priv ( vb - > vb2_queue ) ;
struct fimc_dev * fimc = ctx - > fimc_dev ;
2010-12-01 16:14:59 +03:00
struct fimc_vid_cap * vid_cap = & fimc - > vid_cap ;
2013-05-31 18:37:18 +04:00
struct exynos_video_entity * ve = & vid_cap - > ve ;
2010-12-01 16:14:59 +03:00
unsigned long flags ;
2011-02-07 21:59:46 +03:00
int min_bufs ;
2010-12-01 16:14:59 +03:00
spin_lock_irqsave ( & fimc - > slock , flags ) ;
2020-11-24 11:41:28 +03:00
fimc_prepare_addr ( ctx , & buf - > vb . vb2_buf , & ctx - > d_frame , & buf - > addr ) ;
2011-02-07 21:59:46 +03:00
2011-08-25 03:45:34 +04:00
if ( ! test_bit ( ST_CAPT_SUSPENDED , & fimc - > state ) & &
! test_bit ( ST_CAPT_STREAM , & fimc - > state ) & &
vid_cap - > active_buf_cnt < FIMC_MAX_OUT_BUFS ) {
2011-02-07 21:59:46 +03:00
/* Setup the buffer directly for processing. */
int buf_id = ( vid_cap - > reqbufs_count = = 1 ) ? - 1 :
vid_cap - > buf_index ;
2010-12-01 16:14:59 +03:00
2020-11-24 11:41:28 +03:00
fimc_hw_set_output_addr ( fimc , & buf - > addr , buf_id ) ;
2011-02-07 21:59:46 +03:00
buf - > index = vid_cap - > buf_index ;
2011-06-10 22:36:59 +04:00
fimc_active_queue_add ( vid_cap , buf ) ;
2010-12-01 16:14:59 +03:00
2011-02-07 21:59:46 +03:00
if ( + + vid_cap - > buf_index > = FIMC_MAX_OUT_BUFS )
vid_cap - > buf_index = 0 ;
} else {
fimc_pending_queue_add ( vid_cap , buf ) ;
2010-12-01 16:14:59 +03:00
}
2011-02-07 21:59:46 +03:00
min_bufs = vid_cap - > reqbufs_count > 1 ? 2 : 1 ;
2011-08-26 21:51:00 +04:00
2011-08-29 15:51:49 +04:00
if ( vb2_is_streaming ( & vid_cap - > vbq ) & &
vid_cap - > active_buf_cnt > = min_bufs & &
2011-08-26 21:51:00 +04:00
! test_and_set_bit ( ST_CAPT_STREAM , & fimc - > state ) ) {
2013-02-27 15:13:59 +04:00
int ret ;
2011-02-07 21:59:46 +03:00
fimc_activate_capture ( ctx ) ;
2011-08-26 21:51:00 +04:00
spin_unlock_irqrestore ( & fimc - > slock , flags ) ;
2011-02-07 21:59:46 +03:00
2013-02-27 15:13:59 +04:00
if ( test_and_set_bit ( ST_CAPT_ISP_STREAM , & fimc - > state ) )
return ;
2013-05-31 18:37:22 +04:00
ret = fimc_pipeline_call ( ve , set_stream , 1 ) ;
2013-02-27 15:13:59 +04:00
if ( ret < 0 )
2013-05-31 18:37:18 +04:00
v4l2_err ( & ve - > vdev , " stream on failed: %d \n " , ret ) ;
2011-08-26 21:51:00 +04:00
return ;
}
2010-12-01 16:14:59 +03:00
spin_unlock_irqrestore ( & fimc - > slock , flags ) ;
}
2016-09-09 02:59:10 +03:00
static const struct vb2_ops fimc_capture_qops = {
2010-12-01 16:14:59 +03:00
. queue_setup = queue_setup ,
. buf_prepare = buffer_prepare ,
. buf_queue = buffer_queue ,
2013-03-25 23:36:35 +04:00
. wait_prepare = vb2_ops_wait_prepare ,
. wait_finish = vb2_ops_wait_finish ,
2010-12-01 16:14:59 +03:00
. start_streaming = start_streaming ,
. stop_streaming = stop_streaming ,
} ;
2011-08-25 03:35:30 +04:00
static int fimc_capture_set_default_format ( struct fimc_dev * fimc ) ;
2010-10-07 17:06:16 +04:00
static int fimc_capture_open ( struct file * file )
{
struct fimc_dev * fimc = video_drvdata ( file ) ;
2013-05-31 18:37:19 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
struct exynos_video_entity * ve = & vc - > ve ;
2012-06-27 16:56:17 +04:00
int ret = - EBUSY ;
2010-10-07 17:06:16 +04:00
dbg ( " pid: %d, state: 0x%lx " , task_pid_nr ( current ) , fimc - > state ) ;
2012-12-06 17:26:19 +04:00
mutex_lock ( & fimc - > lock ) ;
2012-06-27 16:56:17 +04:00
2010-10-07 17:06:16 +04:00
if ( fimc_m2m_active ( fimc ) )
2012-06-27 16:56:17 +04:00
goto unlock ;
2010-10-07 17:06:16 +04:00
2011-08-25 03:45:34 +04:00
set_bit ( ST_CAPT_BUSY , & fimc - > state ) ;
2021-04-23 18:19:17 +03:00
ret = pm_runtime_resume_and_get ( & fimc - > pdev - > dev ) ;
if ( ret < 0 )
2012-06-27 16:56:17 +04:00
goto unlock ;
2011-08-26 21:51:00 +04:00
2012-05-17 21:22:10 +04:00
ret = v4l2_fh_open ( file ) ;
2012-06-27 16:56:17 +04:00
if ( ret ) {
2013-05-31 18:37:21 +04:00
pm_runtime_put_sync ( & fimc - > pdev - > dev ) ;
2012-06-27 16:56:17 +04:00
goto unlock ;
}
2012-05-17 21:22:10 +04:00
2013-03-25 23:36:35 +04:00
if ( v4l2_fh_is_singular_file ( file ) ) {
2013-05-31 18:37:20 +04:00
fimc_md_graph_lock ( ve ) ;
2013-05-31 18:37:22 +04:00
ret = fimc_pipeline_call ( ve , open , & ve - > vdev . entity , true ) ;
2013-05-31 18:37:20 +04:00
if ( ret = = 0 )
ve - > vdev . entity . use_count + + ;
fimc_md_graph_unlock ( ve ) ;
2012-05-17 21:22:10 +04:00
2013-05-31 20:47:02 +04:00
if ( ret = = 0 )
ret = fimc_capture_set_default_format ( fimc ) ;
2012-06-27 16:56:17 +04:00
if ( ret < 0 ) {
clear_bit ( ST_CAPT_BUSY , & fimc - > state ) ;
pm_runtime_put_sync ( & fimc - > pdev - > dev ) ;
v4l2_fh_release ( file ) ;
}
}
unlock :
mutex_unlock ( & fimc - > lock ) ;
2011-08-25 02:25:10 +04:00
return ret ;
2010-10-07 17:06:16 +04:00
}
2013-03-25 23:36:35 +04:00
static int fimc_capture_release ( struct file * file )
2010-10-07 17:06:16 +04:00
{
struct fimc_dev * fimc = video_drvdata ( file ) ;
2013-03-25 23:50:50 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
2013-05-31 18:37:20 +04:00
bool close = v4l2_fh_is_singular_file ( file ) ;
2012-06-27 16:56:17 +04:00
int ret ;
2010-10-07 17:06:16 +04:00
dbg ( " pid: %d, state: 0x%lx " , task_pid_nr ( current ) , fimc - > state ) ;
2012-11-22 18:12:16 +04:00
mutex_lock ( & fimc - > lock ) ;
2012-06-27 16:56:17 +04:00
2013-05-31 18:37:20 +04:00
if ( close & & vc - > streaming ) {
2016-11-21 19:48:30 +03:00
media_pipeline_stop ( & vc - > ve . vdev . entity ) ;
2013-05-31 18:37:20 +04:00
vc - > streaming = false ;
}
2013-11-25 12:49:02 +04:00
ret = _vb2_fop_release ( file , NULL ) ;
2013-05-31 18:37:20 +04:00
if ( close ) {
2011-08-25 03:45:34 +04:00
clear_bit ( ST_CAPT_BUSY , & fimc - > state ) ;
2013-05-31 18:37:22 +04:00
fimc_pipeline_call ( & vc - > ve , close ) ;
2011-08-25 03:45:34 +04:00
clear_bit ( ST_CAPT_SUSPENDED , & fimc - > state ) ;
2013-05-31 18:37:20 +04:00
fimc_md_graph_lock ( & vc - > ve ) ;
vc - > ve . vdev . entity . use_count - - ;
fimc_md_graph_unlock ( & vc - > ve ) ;
2010-10-07 17:06:16 +04:00
}
2013-05-31 18:37:21 +04:00
pm_runtime_put_sync ( & fimc - > pdev - > dev ) ;
2012-06-27 16:56:17 +04:00
mutex_unlock ( & fimc - > lock ) ;
return ret ;
2010-10-07 17:06:16 +04:00
}
static const struct v4l2_file_operations fimc_capture_fops = {
. owner = THIS_MODULE ,
. open = fimc_capture_open ,
2013-03-25 23:36:35 +04:00
. release = fimc_capture_release ,
. poll = vb2_fop_poll ,
2010-10-07 17:06:16 +04:00
. unlocked_ioctl = video_ioctl2 ,
2013-03-25 23:36:35 +04:00
. mmap = vb2_fop_mmap ,
2010-10-07 17:06:16 +04:00
} ;
2011-08-25 03:35:30 +04:00
/*
* Format and crop negotiation helpers
*/
static struct fimc_fmt * fimc_capture_try_format ( struct fimc_ctx * ctx ,
u32 * width , u32 * height ,
u32 * code , u32 * fourcc , int pad )
{
bool rotation = ctx - > rotation = = 90 | | ctx - > rotation = = 270 ;
struct fimc_dev * fimc = ctx - > fimc_dev ;
2012-08-02 17:27:46 +04:00
const struct fimc_variant * var = fimc - > variant ;
const struct fimc_pix_limit * pl = var - > pix_limit ;
2011-08-25 03:35:30 +04:00
struct fimc_frame * dst = & ctx - > d_frame ;
u32 depth , min_w , max_w , min_h , align_h = 3 ;
u32 mask = FMT_FLAGS_CAM ;
struct fimc_fmt * ffmt ;
2012-09-24 18:08:45 +04:00
/* Conversion from/to JPEG or User Defined format is not supported */
2011-08-25 03:35:30 +04:00
if ( code & & ctx - > s_frame . fmt & & pad = = FIMC_SD_PAD_SOURCE & &
2012-09-24 18:08:45 +04:00
fimc_fmt_is_user_defined ( ctx - > s_frame . fmt - > color ) )
* code = ctx - > s_frame . fmt - > mbus_code ;
2011-08-25 03:35:30 +04:00
2013-03-20 17:44:39 +04:00
if ( fourcc & & * fourcc ! = V4L2_PIX_FMT_JPEG & & pad = = FIMC_SD_PAD_SOURCE )
2011-08-25 03:35:30 +04:00
mask | = FMT_FLAGS_M2M ;
2013-03-20 17:44:39 +04:00
if ( pad = = FIMC_SD_PAD_SINK_FIFO )
mask = FMT_FLAGS_WRITEBACK ;
2011-08-25 03:35:30 +04:00
ffmt = fimc_find_format ( fourcc , code , mask , 0 ) ;
if ( WARN_ON ( ! ffmt ) )
return NULL ;
2013-03-20 17:44:39 +04:00
2011-08-25 03:35:30 +04:00
if ( code )
* code = ffmt - > mbus_code ;
if ( fourcc )
* fourcc = ffmt - > fourcc ;
2013-03-20 17:44:39 +04:00
if ( pad ! = FIMC_SD_PAD_SOURCE ) {
2012-09-24 18:08:45 +04:00
max_w = fimc_fmt_is_user_defined ( ffmt - > color ) ?
2011-08-25 03:35:30 +04:00
pl - > scaler_dis_w : pl - > scaler_en_w ;
/* Apply the camera input interface pixel constraints */
v4l_bound_align_image ( width , max_t ( u32 , * width , 32 ) , max_w , 4 ,
height , max_t ( u32 , * height , 32 ) ,
FIMC_CAMIF_MAX_HEIGHT ,
2012-09-24 18:08:45 +04:00
fimc_fmt_is_user_defined ( ffmt - > color ) ?
3 : 1 ,
2011-08-25 03:35:30 +04:00
0 ) ;
return ffmt ;
}
/* Can't scale or crop in transparent (JPEG) transfer mode */
2012-09-24 18:08:45 +04:00
if ( fimc_fmt_is_user_defined ( ffmt - > color ) ) {
2011-08-25 03:35:30 +04:00
* width = ctx - > s_frame . f_width ;
* height = ctx - > s_frame . f_height ;
return ffmt ;
}
/* Apply the scaler and the output DMA constraints */
max_w = rotation ? pl - > out_rot_en_w : pl - > out_rot_dis_w ;
2012-04-30 00:46:03 +04:00
if ( ctx - > state & FIMC_COMPOSE ) {
min_w = dst - > offs_h + dst - > width ;
min_h = dst - > offs_v + dst - > height ;
} else {
min_w = var - > min_out_pixsize ;
min_h = var - > min_out_pixsize ;
}
2011-05-27 20:12:23 +04:00
if ( var - > min_vsize_align = = 1 & & ! rotation )
2011-08-25 03:35:30 +04:00
align_h = fimc_fmt_is_rgb ( ffmt - > color ) ? 0 : 1 ;
depth = fimc_get_format_depth ( ffmt ) ;
v4l_bound_align_image ( width , min_w , max_w ,
ffs ( var - > min_out_pixsize ) - 1 ,
height , min_h , FIMC_CAMIF_MAX_HEIGHT ,
align_h ,
64 / ( ALIGN ( depth , 8 ) ) ) ;
dbg ( " pad%d: code: 0x%x, %dx%d. dst fmt: %dx%d " ,
pad , code ? * code : 0 , * width , * height ,
dst - > f_width , dst - > f_height ) ;
return ffmt ;
}
2012-04-30 00:46:03 +04:00
static void fimc_capture_try_selection ( struct fimc_ctx * ctx ,
struct v4l2_rect * r ,
int target )
2011-08-25 03:35:30 +04:00
{
bool rotate = ctx - > rotation = = 90 | | ctx - > rotation = = 270 ;
struct fimc_dev * fimc = ctx - > fimc_dev ;
2012-08-02 17:27:46 +04:00
const struct fimc_variant * var = fimc - > variant ;
const struct fimc_pix_limit * pl = var - > pix_limit ;
2011-08-25 03:35:30 +04:00
struct fimc_frame * sink = & ctx - > s_frame ;
u32 max_w , max_h , min_w = 0 , min_h = 0 , min_sz ;
u32 align_sz = 0 , align_h = 4 ;
u32 max_sc_h , max_sc_v ;
/* In JPEG transparent transfer mode cropping is not supported */
2012-09-24 18:08:45 +04:00
if ( fimc_fmt_is_user_defined ( ctx - > d_frame . fmt - > color ) ) {
2011-08-25 03:35:30 +04:00
r - > width = sink - > f_width ;
r - > height = sink - > f_height ;
r - > left = r - > top = 0 ;
return ;
}
2012-05-20 18:17:12 +04:00
if ( target = = V4L2_SEL_TGT_COMPOSE ) {
2018-03-23 15:54:22 +03:00
u32 tmp_min_h = ffs ( sink - > width ) - 3 ;
u32 tmp_min_v = ffs ( sink - > height ) - 1 ;
2011-08-25 03:35:30 +04:00
if ( ctx - > rotation ! = 90 & & ctx - > rotation ! = 270 )
align_h = 1 ;
2018-03-23 15:54:22 +03:00
max_sc_h = min ( SCALER_MAX_HRATIO , 1 < < tmp_min_h ) ;
max_sc_v = min ( SCALER_MAX_VRATIO , 1 < < tmp_min_v ) ;
2011-08-25 03:35:30 +04:00
min_sz = var - > min_out_pixsize ;
} else {
u32 depth = fimc_get_format_depth ( sink - > fmt ) ;
align_sz = 64 / ALIGN ( depth , 8 ) ;
min_sz = var - > min_inp_pixsize ;
min_w = min_h = min_sz ;
max_sc_h = max_sc_v = 1 ;
}
/*
2012-04-30 00:46:03 +04:00
* For the compose rectangle the following constraints must be met :
2011-08-25 03:35:30 +04:00
* - it must fit in the sink pad format rectangle ( f_width / f_height ) ;
* - maximum downscaling ratio is 64 ;
* - maximum crop size depends if the rotator is used or not ;
* - the sink pad format width / height must be 4 multiple of the
* prescaler ratios determined by sink pad size and source pad crop ,
* the prescaler ratio is returned by fimc_get_scaler_factor ( ) .
*/
max_w = min_t ( u32 ,
rotate ? pl - > out_rot_en_w : pl - > out_rot_dis_w ,
rotate ? sink - > f_height : sink - > f_width ) ;
max_h = min_t ( u32 , FIMC_CAMIF_MAX_HEIGHT , sink - > f_height ) ;
2012-04-30 00:46:03 +04:00
2012-05-20 18:17:12 +04:00
if ( target = = V4L2_SEL_TGT_COMPOSE ) {
2011-08-25 03:35:30 +04:00
min_w = min_t ( u32 , max_w , sink - > f_width / max_sc_h ) ;
min_h = min_t ( u32 , max_h , sink - > f_height / max_sc_v ) ;
if ( rotate ) {
swap ( max_sc_h , max_sc_v ) ;
swap ( min_w , min_h ) ;
}
}
v4l_bound_align_image ( & r - > width , min_w , max_w , ffs ( min_sz ) - 1 ,
& r - > height , min_h , max_h , align_h ,
align_sz ) ;
2012-04-30 00:46:03 +04:00
/* Adjust left/top if crop/compose rectangle is out of bounds */
2011-08-25 03:35:30 +04:00
r - > left = clamp_t ( u32 , r - > left , 0 , sink - > f_width - r - > width ) ;
r - > top = clamp_t ( u32 , r - > top , 0 , sink - > f_height - r - > height ) ;
r - > left = round_down ( r - > left , var - > hor_offs_align ) ;
2012-04-30 00:46:03 +04:00
dbg ( " target %#x: (%d,%d)/%dx%d, sink fmt: %dx%d " ,
target , r - > left , r - > top , r - > width , r - > height ,
2011-08-25 03:35:30 +04:00
sink - > f_width , sink - > f_height ) ;
}
/*
* The video node ioctl operations
*/
2013-04-23 18:36:04 +04:00
static int fimc_cap_querycap ( struct file * file , void * priv ,
2010-10-07 17:06:16 +04:00
struct v4l2_capability * cap )
{
2011-06-10 22:36:50 +04:00
struct fimc_dev * fimc = video_drvdata ( file ) ;
2010-10-07 17:06:16 +04:00
2019-06-04 10:06:24 +03:00
__fimc_vidioc_querycap ( & fimc - > pdev - > dev , cap ) ;
2010-10-07 17:06:16 +04:00
return 0 ;
}
2019-06-04 10:06:25 +03:00
static int fimc_cap_enum_fmt ( struct file * file , void * priv ,
struct v4l2_fmtdesc * f )
2011-06-13 18:09:40 +04:00
{
struct fimc_fmt * fmt ;
fmt = fimc_find_format ( NULL , NULL , FMT_FLAGS_CAM | FMT_FLAGS_M2M ,
f - > index ) ;
if ( ! fmt )
return - EINVAL ;
f - > pixelformat = fmt - > fourcc ;
return 0 ;
}
2012-12-03 13:24:32 +04:00
static struct media_entity * fimc_pipeline_get_head ( struct media_entity * me )
{
struct media_pad * pad = & me - > pads [ 0 ] ;
while ( ! ( pad - > flags & MEDIA_PAD_FL_SOURCE ) ) {
2013-06-03 12:16:13 +04:00
pad = media_entity_remote_pad ( pad ) ;
2012-12-03 13:24:32 +04:00
if ( ! pad )
break ;
me = pad - > entity ;
pad = & me - > pads [ 0 ] ;
}
return me ;
}
2011-08-25 03:35:30 +04:00
/**
* fimc_pipeline_try_format - negotiate and / or set formats at pipeline
* elements
* @ ctx : FIMC capture context
* @ tfmt : media bus format to try / set on subdevs
* @ fmt_id : fimc pixel format id corresponding to returned @ tfmt ( output )
* @ set : true to set format on subdevs , false to try only
*/
static int fimc_pipeline_try_format ( struct fimc_ctx * ctx ,
struct v4l2_mbus_framefmt * tfmt ,
struct fimc_fmt * * fmt_id ,
bool set )
{
struct fimc_dev * fimc = ctx - > fimc_dev ;
2013-05-31 18:37:22 +04:00
struct fimc_pipeline * p = to_fimc_pipeline ( fimc - > vid_cap . ve . pipe ) ;
struct v4l2_subdev * sd = p - > subdevs [ IDX_SENSOR ] ;
2011-08-25 03:35:30 +04:00
struct v4l2_subdev_format sfmt ;
struct v4l2_mbus_framefmt * mf = & sfmt . format ;
2012-12-03 13:24:32 +04:00
struct media_entity * me ;
struct fimc_fmt * ffmt ;
struct media_pad * pad ;
int ret , i = 1 ;
u32 fcc ;
2011-08-25 03:35:30 +04:00
if ( WARN_ON ( ! sd | | ! tfmt ) )
return - EINVAL ;
2010-10-07 17:06:16 +04:00
2011-08-25 03:35:30 +04:00
memset ( & sfmt , 0 , sizeof ( sfmt ) ) ;
sfmt . format = * tfmt ;
sfmt . which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY ;
2012-12-03 13:24:32 +04:00
me = fimc_pipeline_get_head ( & sd - > entity ) ;
2011-08-25 03:35:30 +04:00
while ( 1 ) {
ffmt = fimc_find_format ( NULL , mf - > code ! = 0 ? & mf - > code : NULL ,
FMT_FLAGS_CAM , i + + ) ;
if ( ffmt = = NULL ) {
/*
* Notify user - space if common pixel code for
* host and sensor does not exist .
*/
return - EINVAL ;
}
mf - > code = tfmt - > code = ffmt - > mbus_code ;
2010-10-07 17:06:16 +04:00
2012-12-03 13:24:32 +04:00
/* set format on all pipeline subdevs */
while ( me ! = & fimc - > vid_cap . subdev . entity ) {
sd = media_entity_to_v4l2_subdev ( me ) ;
sfmt . pad = 0 ;
ret = v4l2_subdev_call ( sd , pad , set_fmt , NULL , & sfmt ) ;
if ( ret )
return ret ;
if ( me - > pads [ 0 ] . flags & MEDIA_PAD_FL_SINK ) {
sfmt . pad = me - > num_pads - 1 ;
mf - > code = tfmt - > code ;
ret = v4l2_subdev_call ( sd , pad , set_fmt , NULL ,
& sfmt ) ;
if ( ret )
return ret ;
}
2013-06-03 12:16:13 +04:00
pad = media_entity_remote_pad ( & me - > pads [ sfmt . pad ] ) ;
2012-12-03 13:24:32 +04:00
if ( ! pad )
return - EINVAL ;
me = pad - > entity ;
2011-08-25 03:35:30 +04:00
}
2010-10-07 17:06:16 +04:00
2012-12-03 13:24:32 +04:00
if ( mf - > code ! = tfmt - > code )
continue ;
fcc = ffmt - > fourcc ;
tfmt - > width = mf - > width ;
tfmt - > height = mf - > height ;
ffmt = fimc_capture_try_format ( ctx , & tfmt - > width , & tfmt - > height ,
2013-03-20 17:44:39 +04:00
NULL , & fcc , FIMC_SD_PAD_SINK_CAM ) ;
2012-12-03 13:24:32 +04:00
ffmt = fimc_capture_try_format ( ctx , & tfmt - > width , & tfmt - > height ,
NULL , & fcc , FIMC_SD_PAD_SOURCE ) ;
if ( ffmt & & ffmt - > mbus_code )
mf - > code = ffmt - > mbus_code ;
if ( mf - > width ! = tfmt - > width | | mf - > height ! = tfmt - > height )
continue ;
tfmt - > code = mf - > code ;
break ;
2011-08-25 03:35:30 +04:00
}
2010-10-07 17:06:16 +04:00
2011-08-25 03:35:30 +04:00
if ( fmt_id & & ffmt )
* fmt_id = ffmt ;
* tfmt = * mf ;
2010-10-07 17:06:16 +04:00
2011-08-25 03:35:30 +04:00
return 0 ;
}
2010-10-07 17:06:16 +04:00
2012-09-24 18:08:45 +04:00
/**
* fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters
* @ sensor : pointer to the sensor subdev
* @ plane_fmt : provides plane sizes corresponding to the frame layout entries
2017-11-29 12:32:51 +03:00
* @ num_planes : number of planes
2012-09-24 18:08:45 +04:00
* @ try : true to set the frame parameters , false to query only
*
* This function is used by this driver only for compressed / blob data formats .
*/
static int fimc_get_sensor_frame_desc ( struct v4l2_subdev * sensor ,
struct v4l2_plane_pix_format * plane_fmt ,
unsigned int num_planes , bool try )
{
struct v4l2_mbus_frame_desc fd ;
int i , ret ;
2012-11-22 19:13:27 +04:00
int pad ;
2012-09-24 18:08:45 +04:00
for ( i = 0 ; i < num_planes ; i + + )
fd . entry [ i ] . length = plane_fmt [ i ] . sizeimage ;
2012-11-22 19:13:27 +04:00
pad = sensor - > entity . num_pads - 1 ;
2012-09-24 18:08:45 +04:00
if ( try )
2012-11-22 19:13:27 +04:00
ret = v4l2_subdev_call ( sensor , pad , set_frame_desc , pad , & fd ) ;
2012-09-24 18:08:45 +04:00
else
2012-11-22 19:13:27 +04:00
ret = v4l2_subdev_call ( sensor , pad , get_frame_desc , pad , & fd ) ;
2012-09-24 18:08:45 +04:00
if ( ret < 0 )
return ret ;
if ( num_planes ! = fd . num_entries )
return - EINVAL ;
for ( i = 0 ; i < num_planes ; i + + )
plane_fmt [ i ] . sizeimage = fd . entry [ i ] . length ;
if ( fd . entry [ 0 ] . length > FIMC_MAX_JPEG_BUF_SIZE ) {
v4l2_err ( sensor - > v4l2_dev , " Unsupported buffer size: %u \n " ,
fd . entry [ 0 ] . length ) ;
return - EINVAL ;
}
return 0 ;
}
2011-06-10 22:36:50 +04:00
static int fimc_cap_g_fmt_mplane ( struct file * file , void * fh ,
struct v4l2_format * f )
{
struct fimc_dev * fimc = video_drvdata ( file ) ;
2013-01-11 13:36:19 +04:00
__fimc_get_format ( & fimc - > vid_cap . ctx - > d_frame , f ) ;
return 0 ;
2011-06-10 22:36:50 +04:00
}
2013-05-31 20:47:02 +04:00
/*
* Try or set format on the fimc . X . capture video node and additionally
* on the whole pipeline if @ try is false .
* Locking : the caller must _not_ hold the graph mutex .
*/
static int __video_try_or_set_format ( struct fimc_dev * fimc ,
struct v4l2_format * f , bool try ,
struct fimc_fmt * * inp_fmt ,
struct fimc_fmt * * out_fmt )
2011-06-10 22:36:50 +04:00
{
2011-08-25 03:35:30 +04:00
struct v4l2_pix_format_mplane * pix = & f - > fmt . pix_mp ;
2013-05-31 20:47:02 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
struct exynos_video_entity * ve = & vc - > ve ;
struct fimc_ctx * ctx = vc - > ctx ;
unsigned int width = 0 , height = 0 ;
2012-12-06 17:26:19 +04:00
int ret = 0 ;
2013-05-31 20:47:02 +04:00
/* Pre-configure format at the camera input interface, for JPEG only */
2012-09-24 18:08:45 +04:00
if ( fimc_jpeg_fourcc ( pix - > pixelformat ) ) {
2011-08-25 03:35:30 +04:00
fimc_capture_try_format ( ctx , & pix - > width , & pix - > height ,
NULL , & pix - > pixelformat ,
2013-03-20 17:44:39 +04:00
FIMC_SD_PAD_SINK_CAM ) ;
2013-05-31 20:47:02 +04:00
if ( try ) {
width = pix - > width ;
height = pix - > height ;
} else {
ctx - > s_frame . f_width = pix - > width ;
ctx - > s_frame . f_height = pix - > height ;
}
2011-08-25 03:35:30 +04:00
}
2013-05-31 20:47:02 +04:00
/* Try the format at the scaler and the DMA output */
* out_fmt = fimc_capture_try_format ( ctx , & pix - > width , & pix - > height ,
NULL , & pix - > pixelformat ,
FIMC_SD_PAD_SOURCE ) ;
if ( * out_fmt = = NULL )
2013-05-31 18:37:20 +04:00
return - EINVAL ;
2011-08-25 03:35:30 +04:00
2013-05-31 20:47:02 +04:00
/* Restore image width/height for JPEG (no resizing supported). */
if ( try & & fimc_jpeg_fourcc ( pix - > pixelformat ) ) {
pix - > width = width ;
pix - > height = height ;
}
/* Try to match format at the host and the sensor */
if ( ! vc - > user_subdev_api ) {
struct v4l2_mbus_framefmt mbus_fmt ;
struct v4l2_mbus_framefmt * mf ;
mf = try ? & mbus_fmt : & fimc - > vid_cap . ci_fmt ;
mf - > code = ( * out_fmt ) - > mbus_code ;
mf - > width = pix - > width ;
mf - > height = pix - > height ;
2013-05-31 18:37:20 +04:00
fimc_md_graph_lock ( ve ) ;
2013-05-31 20:47:02 +04:00
ret = fimc_pipeline_try_format ( ctx , mf , inp_fmt , try ) ;
2013-05-31 18:37:20 +04:00
fimc_md_graph_unlock ( ve ) ;
2013-05-31 20:47:02 +04:00
if ( ret < 0 )
return ret ;
pix - > width = mf - > width ;
pix - > height = mf - > height ;
2011-08-25 03:35:30 +04:00
}
2011-06-10 22:36:50 +04:00
2013-05-31 20:47:02 +04:00
fimc_adjust_mplane_format ( * out_fmt , pix - > width , pix - > height , pix ) ;
if ( ( * out_fmt ) - > flags & FMT_FLAGS_COMPRESSED ) {
struct v4l2_subdev * sensor ;
2012-09-24 18:08:45 +04:00
2013-05-31 18:37:22 +04:00
fimc_md_graph_lock ( ve ) ;
sensor = __fimc_md_get_subdev ( ve - > pipe , IDX_SENSOR ) ;
if ( sensor )
fimc_get_sensor_frame_desc ( sensor , pix - > plane_fmt ,
2013-05-31 20:47:02 +04:00
( * out_fmt ) - > memplanes , try ) ;
2013-05-31 18:37:22 +04:00
else
ret = - EPIPE ;
fimc_md_graph_unlock ( ve ) ;
}
2012-09-24 18:08:45 +04:00
2012-12-06 17:26:19 +04:00
return ret ;
2011-06-10 22:36:50 +04:00
}
2013-05-31 20:47:02 +04:00
static int fimc_cap_try_fmt_mplane ( struct file * file , void * fh ,
struct v4l2_format * f )
{
struct fimc_dev * fimc = video_drvdata ( file ) ;
struct fimc_fmt * out_fmt = NULL , * inp_fmt = NULL ;
return __video_try_or_set_format ( fimc , f , true , & inp_fmt , & out_fmt ) ;
}
2012-09-24 18:08:45 +04:00
static void fimc_capture_mark_jpeg_xfer ( struct fimc_ctx * ctx ,
enum fimc_color_fmt color )
2011-08-26 21:57:06 +04:00
{
2012-09-24 18:08:45 +04:00
bool jpeg = fimc_fmt_is_user_defined ( color ) ;
2011-08-26 21:57:06 +04:00
ctx - > scaler . enabled = ! jpeg ;
fimc_ctrls_activate ( ctx , ! jpeg ) ;
if ( jpeg )
set_bit ( ST_CAPT_JPEG , & ctx - > fimc_dev - > state ) ;
else
clear_bit ( ST_CAPT_JPEG , & ctx - > fimc_dev - > state ) ;
}
2012-12-06 17:26:19 +04:00
static int __fimc_capture_set_format ( struct fimc_dev * fimc ,
struct v4l2_format * f )
2010-10-07 17:06:16 +04:00
{
2013-05-31 20:47:02 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
struct fimc_ctx * ctx = vc - > ctx ;
2011-08-25 03:35:30 +04:00
struct v4l2_pix_format_mplane * pix = & f - > fmt . pix_mp ;
struct fimc_frame * ff = & ctx - > d_frame ;
2013-05-31 20:47:02 +04:00
struct fimc_fmt * inp_fmt = NULL ;
2011-08-25 03:35:30 +04:00
int ret , i ;
2010-10-07 17:06:16 +04:00
2011-08-25 03:35:30 +04:00
if ( vb2_is_busy ( & fimc - > vid_cap . vbq ) )
2010-12-08 20:05:08 +03:00
return - EBUSY ;
2010-10-07 17:06:16 +04:00
2013-05-31 20:47:02 +04:00
ret = __video_try_or_set_format ( fimc , f , false , & inp_fmt , & ff - > fmt ) ;
if ( ret < 0 )
return ret ;
2011-12-01 21:02:24 +04:00
/* Update RGB Alpha control state and value range */
fimc_alpha_ctrl_update ( ctx ) ;
2013-01-11 13:36:19 +04:00
for ( i = 0 ; i < ff - > fmt - > memplanes ; i + + ) {
ff - > bytesperline [ i ] = pix - > plane_fmt [ i ] . bytesperline ;
2012-05-16 22:00:26 +04:00
ff - > payload [ i ] = pix - > plane_fmt [ i ] . sizeimage ;
2013-01-11 13:36:19 +04:00
}
2011-08-25 03:35:30 +04:00
set_frame_bounds ( ff , pix - > width , pix - > height ) ;
/* Reset the composition rectangle if not yet configured */
2012-04-30 00:46:03 +04:00
if ( ! ( ctx - > state & FIMC_COMPOSE ) )
2011-08-25 03:35:30 +04:00
set_frame_crop ( ff , 0 , 0 , pix - > width , pix - > height ) ;
2012-09-24 18:08:45 +04:00
fimc_capture_mark_jpeg_xfer ( ctx , ff - > fmt - > color ) ;
2011-08-26 21:57:06 +04:00
2011-08-25 03:35:30 +04:00
/* Reset cropping and set format at the camera interface input */
2013-05-31 20:47:02 +04:00
if ( ! vc - > user_subdev_api ) {
ctx - > s_frame . fmt = inp_fmt ;
2011-08-25 03:35:30 +04:00
set_frame_bounds ( & ctx - > s_frame , pix - > width , pix - > height ) ;
set_frame_crop ( & ctx - > s_frame , 0 , 0 , pix - > width , pix - > height ) ;
2011-04-08 16:11:43 +04:00
}
2010-12-08 20:05:08 +03:00
2011-08-25 03:35:30 +04:00
return ret ;
}
2010-10-07 17:06:16 +04:00
2011-08-25 03:35:30 +04:00
static int fimc_cap_s_fmt_mplane ( struct file * file , void * priv ,
struct v4l2_format * f )
{
struct fimc_dev * fimc = video_drvdata ( file ) ;
2012-12-06 17:26:19 +04:00
2013-05-31 20:47:02 +04:00
return __fimc_capture_set_format ( fimc , f ) ;
2010-10-07 17:06:16 +04:00
}
static int fimc_cap_enum_input ( struct file * file , void * priv ,
2011-07-27 01:27:59 +04:00
struct v4l2_input * i )
2010-10-07 17:06:16 +04:00
{
2011-06-10 22:36:50 +04:00
struct fimc_dev * fimc = video_drvdata ( file ) ;
2013-05-31 18:37:22 +04:00
struct exynos_video_entity * ve = & fimc - > vid_cap . ve ;
struct v4l2_subdev * sd ;
2010-10-07 17:06:16 +04:00
2011-07-27 01:27:59 +04:00
if ( i - > index ! = 0 )
2010-10-07 17:06:16 +04:00
return - EINVAL ;
i - > type = V4L2_INPUT_TYPE_CAMERA ;
2013-05-31 18:37:22 +04:00
fimc_md_graph_lock ( ve ) ;
sd = __fimc_md_get_subdev ( ve - > pipe , IDX_SENSOR ) ;
fimc_md_graph_unlock ( ve ) ;
2011-08-26 21:51:00 +04:00
if ( sd )
2018-09-10 15:19:14 +03:00
strscpy ( i - > name , sd - > name , sizeof ( i - > name ) ) ;
2013-05-31 18:37:22 +04:00
2010-10-07 17:06:16 +04:00
return 0 ;
}
2011-07-27 01:27:59 +04:00
static int fimc_cap_s_input ( struct file * file , void * priv , unsigned int i )
2010-10-07 17:06:16 +04:00
{
2011-07-27 01:27:59 +04:00
return i = = 0 ? i : - EINVAL ;
2010-10-07 17:06:16 +04:00
}
2011-07-27 01:27:59 +04:00
static int fimc_cap_g_input ( struct file * file , void * priv , unsigned int * i )
2010-10-07 17:06:16 +04:00
{
2011-07-27 01:27:59 +04:00
* i = 0 ;
2010-10-07 17:06:16 +04:00
return 0 ;
}
2011-08-25 03:35:30 +04:00
/**
* fimc_pipeline_validate - check for formats inconsistencies
* between source and sink pad of each link
2017-11-29 12:32:51 +03:00
* @ fimc : the FIMC device this context applies to
2011-08-25 03:35:30 +04:00
*
* Return 0 if all formats match or - EPIPE otherwise .
*/
static int fimc_pipeline_validate ( struct fimc_dev * fimc )
{
struct v4l2_subdev_format sink_fmt , src_fmt ;
2013-03-20 17:44:39 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
struct v4l2_subdev * sd = & vc - > subdev ;
2013-05-31 18:37:22 +04:00
struct fimc_pipeline * p = to_fimc_pipeline ( vc - > ve . pipe ) ;
2013-03-20 17:44:39 +04:00
struct media_pad * sink_pad , * src_pad ;
int i , ret ;
2011-08-25 03:35:30 +04:00
while ( 1 ) {
2013-03-20 17:44:39 +04:00
/*
* Find current entity sink pad and any remote sink pad linked
* to it . We stop if there is no sink pad in current entity or
* it is not linked to any other remote entity .
*/
src_pad = NULL ;
for ( i = 0 ; i < sd - > entity . num_pads ; i + + ) {
struct media_pad * p = & sd - > entity . pads [ i ] ;
if ( p - > flags & MEDIA_PAD_FL_SINK ) {
sink_pad = p ;
2013-06-03 12:16:13 +04:00
src_pad = media_entity_remote_pad ( sink_pad ) ;
2013-03-20 17:44:39 +04:00
if ( src_pad )
break ;
}
}
2015-05-08 04:12:32 +03:00
if ( ! src_pad | | ! is_media_entity_v4l2_subdev ( src_pad - > entity ) )
2011-08-25 03:35:30 +04:00
break ;
2013-03-20 17:44:39 +04:00
2011-08-25 03:35:30 +04:00
/* Don't call FIMC subdev operation to avoid nested locking */
2013-03-20 17:44:39 +04:00
if ( sd = = & vc - > subdev ) {
struct fimc_frame * ff = & vc - > ctx - > s_frame ;
2011-08-25 03:35:30 +04:00
sink_fmt . format . width = ff - > f_width ;
sink_fmt . format . height = ff - > f_height ;
sink_fmt . format . code = ff - > fmt ? ff - > fmt - > mbus_code : 0 ;
} else {
2013-03-20 17:44:39 +04:00
sink_fmt . pad = sink_pad - > index ;
2011-08-25 03:35:30 +04:00
sink_fmt . which = V4L2_SUBDEV_FORMAT_ACTIVE ;
ret = v4l2_subdev_call ( sd , pad , get_fmt , NULL , & sink_fmt ) ;
if ( ret < 0 & & ret ! = - ENOIOCTLCMD )
return - EPIPE ;
}
2013-03-20 17:44:39 +04:00
/* Retrieve format at the source pad */
sd = media_entity_to_v4l2_subdev ( src_pad - > entity ) ;
src_fmt . pad = src_pad - > index ;
2011-08-25 03:35:30 +04:00
src_fmt . which = V4L2_SUBDEV_FORMAT_ACTIVE ;
ret = v4l2_subdev_call ( sd , pad , get_fmt , NULL , & src_fmt ) ;
if ( ret < 0 & & ret ! = - ENOIOCTLCMD )
return - EPIPE ;
if ( src_fmt . format . width ! = sink_fmt . format . width | |
src_fmt . format . height ! = sink_fmt . format . height | |
src_fmt . format . code ! = sink_fmt . format . code )
return - EPIPE ;
2012-09-24 18:08:45 +04:00
2013-05-31 18:37:22 +04:00
if ( sd = = p - > subdevs [ IDX_SENSOR ] & &
2012-09-24 18:08:45 +04:00
fimc_user_defined_mbus_fmt ( src_fmt . format . code ) ) {
struct v4l2_plane_pix_format plane_fmt [ FIMC_MAX_PLANES ] ;
2013-03-20 17:44:39 +04:00
struct fimc_frame * frame = & vc - > ctx - > d_frame ;
2012-09-24 18:08:45 +04:00
unsigned int i ;
ret = fimc_get_sensor_frame_desc ( sd , plane_fmt ,
frame - > fmt - > memplanes ,
false ) ;
if ( ret < 0 )
return - EPIPE ;
for ( i = 0 ; i < frame - > fmt - > memplanes ; i + + )
if ( frame - > payload [ i ] < plane_fmt [ i ] . sizeimage )
return - EPIPE ;
}
2011-08-25 03:35:30 +04:00
}
return 0 ;
}
2010-10-07 17:06:16 +04:00
static int fimc_cap_streamon ( struct file * file , void * priv ,
2010-12-01 16:14:59 +03:00
enum v4l2_buf_type type )
2010-10-07 17:06:16 +04:00
{
2011-06-10 22:36:50 +04:00
struct fimc_dev * fimc = video_drvdata ( file ) ;
2013-03-20 17:35:43 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
2013-05-31 18:37:18 +04:00
struct media_entity * entity = & vc - > ve . vdev . entity ;
2013-03-20 17:44:39 +04:00
struct fimc_source_info * si = NULL ;
struct v4l2_subdev * sd ;
2011-08-25 03:35:30 +04:00
int ret ;
2010-10-07 17:06:16 +04:00
2011-08-26 21:51:00 +04:00
if ( fimc_capture_active ( fimc ) )
2010-12-01 16:25:18 +03:00
return - EBUSY ;
2010-10-07 17:06:16 +04:00
2016-11-21 19:48:30 +03:00
ret = media_pipeline_start ( entity , & vc - > ve . pipe - > mp ) ;
2012-05-25 14:08:05 +04:00
if ( ret < 0 )
return ret ;
2010-10-07 17:06:16 +04:00
2013-05-31 18:37:22 +04:00
sd = __fimc_md_get_subdev ( vc - > ve . pipe , IDX_SENSOR ) ;
2013-03-20 17:44:39 +04:00
if ( sd )
si = v4l2_get_subdev_hostdata ( sd ) ;
if ( si = = NULL ) {
ret = - EPIPE ;
goto err_p_stop ;
}
/*
* Save configuration data related to currently attached image
* sensor or other data source , e . g . FIMC - IS .
*/
vc - > source_config = * si ;
if ( vc - > input = = GRP_ID_FIMC_IS )
vc - > source_config . fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK ;
2013-03-20 17:35:43 +04:00
if ( vc - > user_subdev_api ) {
2011-08-25 03:35:30 +04:00
ret = fimc_pipeline_validate ( fimc ) ;
2013-03-20 17:35:43 +04:00
if ( ret < 0 )
goto err_p_stop ;
2011-08-25 03:35:30 +04:00
}
2013-03-20 17:35:43 +04:00
2013-03-25 23:36:35 +04:00
ret = vb2_ioctl_streamon ( file , priv , type ) ;
2013-03-25 23:50:50 +04:00
if ( ! ret ) {
vc - > streaming = true ;
2013-03-20 17:35:43 +04:00
return ret ;
2013-03-25 23:50:50 +04:00
}
2013-03-20 17:35:43 +04:00
err_p_stop :
2016-11-21 19:48:30 +03:00
media_pipeline_stop ( entity ) ;
2013-03-20 17:35:43 +04:00
return ret ;
2010-10-07 17:06:16 +04:00
}
static int fimc_cap_streamoff ( struct file * file , void * priv ,
2010-12-01 16:25:18 +03:00
enum v4l2_buf_type type )
2010-10-07 17:06:16 +04:00
{
2011-06-10 22:36:50 +04:00
struct fimc_dev * fimc = video_drvdata ( file ) ;
2013-05-31 18:37:18 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
2011-08-26 21:51:00 +04:00
int ret ;
2010-10-07 17:06:16 +04:00
2013-03-25 23:36:35 +04:00
ret = vb2_ioctl_streamoff ( file , priv , type ) ;
2013-03-25 23:50:50 +04:00
if ( ret < 0 )
return ret ;
2013-03-20 17:35:43 +04:00
2020-07-31 02:01:13 +03:00
if ( vc - > streaming ) {
media_pipeline_stop ( & vc - > ve . vdev . entity ) ;
vc - > streaming = false ;
}
2013-03-25 23:50:50 +04:00
return 0 ;
2010-10-07 17:06:16 +04:00
}
static int fimc_cap_reqbufs ( struct file * file , void * priv ,
2010-12-08 20:05:08 +03:00
struct v4l2_requestbuffers * reqbufs )
2010-10-07 17:06:16 +04:00
{
2011-06-10 22:36:50 +04:00
struct fimc_dev * fimc = video_drvdata ( file ) ;
2013-03-25 23:36:35 +04:00
int ret ;
ret = vb2_ioctl_reqbufs ( file , priv , reqbufs ) ;
2010-10-07 17:06:16 +04:00
if ( ! ret )
2011-06-10 22:36:50 +04:00
fimc - > vid_cap . reqbufs_count = reqbufs - > count ;
2012-01-30 21:56:59 +04:00
2013-03-25 23:36:35 +04:00
return ret ;
2012-01-30 21:56:59 +04:00
}
2012-02-05 00:03:54 +04:00
static int fimc_cap_g_selection ( struct file * file , void * fh ,
struct v4l2_selection * s )
2010-11-25 17:01:51 +03:00
{
2011-06-10 22:36:50 +04:00
struct fimc_dev * fimc = video_drvdata ( file ) ;
2012-02-05 00:03:54 +04:00
struct fimc_ctx * ctx = fimc - > vid_cap . ctx ;
struct fimc_frame * f = & ctx - > s_frame ;
2010-11-25 17:01:51 +03:00
2017-05-08 17:35:05 +03:00
if ( s - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
2010-11-25 17:01:51 +03:00
return - EINVAL ;
2012-02-05 00:03:54 +04:00
switch ( s - > target ) {
case V4L2_SEL_TGT_COMPOSE_DEFAULT :
case V4L2_SEL_TGT_COMPOSE_BOUNDS :
f = & ctx - > d_frame ;
2020-07-25 01:10:14 +03:00
fallthrough ;
2012-02-05 00:03:54 +04:00
case V4L2_SEL_TGT_CROP_BOUNDS :
case V4L2_SEL_TGT_CROP_DEFAULT :
s - > r . left = 0 ;
s - > r . top = 0 ;
s - > r . width = f - > o_width ;
s - > r . height = f - > o_height ;
return 0 ;
2010-11-25 17:01:51 +03:00
2012-05-20 18:17:12 +04:00
case V4L2_SEL_TGT_COMPOSE :
2012-02-05 00:03:54 +04:00
f = & ctx - > d_frame ;
2020-07-25 01:10:14 +03:00
fallthrough ;
2012-05-20 18:17:12 +04:00
case V4L2_SEL_TGT_CROP :
2012-02-05 00:03:54 +04:00
s - > r . left = f - > offs_h ;
s - > r . top = f - > offs_v ;
s - > r . width = f - > width ;
s - > r . height = f - > height ;
return 0 ;
}
return - EINVAL ;
2010-11-25 17:01:51 +03:00
}
2012-02-05 00:03:54 +04:00
static int fimc_cap_s_selection ( struct file * file , void * fh ,
struct v4l2_selection * s )
2010-10-07 17:06:16 +04:00
{
2011-06-10 22:36:50 +04:00
struct fimc_dev * fimc = video_drvdata ( file ) ;
struct fimc_ctx * ctx = fimc - > vid_cap . ctx ;
2012-02-05 00:03:54 +04:00
struct v4l2_rect rect = s - > r ;
struct fimc_frame * f ;
2011-08-25 03:35:30 +04:00
unsigned long flags ;
2012-02-05 00:03:54 +04:00
2017-05-08 17:35:05 +03:00
if ( s - > type ! = V4L2_BUF_TYPE_VIDEO_CAPTURE )
2012-02-05 00:03:54 +04:00
return - EINVAL ;
2012-05-20 18:17:12 +04:00
if ( s - > target = = V4L2_SEL_TGT_COMPOSE )
2012-02-05 00:03:54 +04:00
f = & ctx - > d_frame ;
2012-05-20 18:17:12 +04:00
else if ( s - > target = = V4L2_SEL_TGT_CROP )
2012-02-05 00:03:54 +04:00
f = & ctx - > s_frame ;
2012-04-30 00:46:03 +04:00
else
2012-02-05 00:03:54 +04:00
return - EINVAL ;
2012-04-30 00:46:03 +04:00
fimc_capture_try_selection ( ctx , & rect , s - > target ) ;
2012-02-05 00:03:54 +04:00
if ( s - > flags & V4L2_SEL_FLAG_LE & &
2020-05-28 16:26:05 +03:00
! v4l2_rect_enclosed ( & rect , & s - > r ) )
2012-02-05 00:03:54 +04:00
return - ERANGE ;
2010-10-07 17:06:16 +04:00
2012-02-05 00:03:54 +04:00
if ( s - > flags & V4L2_SEL_FLAG_GE & &
2020-05-28 16:26:05 +03:00
! v4l2_rect_enclosed ( & s - > r , & rect ) )
2012-02-05 00:03:54 +04:00
return - ERANGE ;
2010-10-07 17:06:16 +04:00
2012-02-05 00:03:54 +04:00
s - > r = rect ;
2011-08-25 03:35:30 +04:00
spin_lock_irqsave ( & fimc - > slock , flags ) ;
2012-02-05 00:03:54 +04:00
set_frame_crop ( f , s - > r . left , s - > r . top , s - > r . width ,
s - > r . height ) ;
2011-08-25 03:35:30 +04:00
spin_unlock_irqrestore ( & fimc - > slock , flags ) ;
2010-12-01 16:25:18 +03:00
2012-02-05 00:03:54 +04:00
set_bit ( ST_CAPT_APPLY_CFG , & fimc - > state ) ;
2010-12-01 16:25:18 +03:00
return 0 ;
2010-10-07 17:06:16 +04:00
}
static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
2013-04-23 18:36:04 +04:00
. vidioc_querycap = fimc_cap_querycap ,
2010-10-07 17:06:16 +04:00
2019-06-04 10:06:25 +03:00
. vidioc_enum_fmt_vid_cap = fimc_cap_enum_fmt ,
2011-06-10 22:36:50 +04:00
. vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane ,
2010-12-08 20:05:08 +03:00
. vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane ,
2011-06-10 22:36:50 +04:00
. vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane ,
2010-10-07 17:06:16 +04:00
. vidioc_reqbufs = fimc_cap_reqbufs ,
2013-03-25 23:36:35 +04:00
. vidioc_querybuf = vb2_ioctl_querybuf ,
. vidioc_qbuf = vb2_ioctl_qbuf ,
. vidioc_dqbuf = vb2_ioctl_dqbuf ,
. vidioc_expbuf = vb2_ioctl_expbuf ,
. vidioc_prepare_buf = vb2_ioctl_prepare_buf ,
. vidioc_create_bufs = vb2_ioctl_create_bufs ,
2012-01-30 21:56:59 +04:00
2010-10-07 17:06:16 +04:00
. vidioc_streamon = fimc_cap_streamon ,
. vidioc_streamoff = fimc_cap_streamoff ,
2012-02-05 00:03:54 +04:00
. vidioc_g_selection = fimc_cap_g_selection ,
. vidioc_s_selection = fimc_cap_s_selection ,
2010-10-07 17:06:16 +04:00
. vidioc_enum_input = fimc_cap_enum_input ,
. vidioc_s_input = fimc_cap_s_input ,
. vidioc_g_input = fimc_cap_g_input ,
} ;
2011-08-25 03:35:30 +04:00
/* Capture subdev media entity operations */
2011-08-25 02:28:18 +04:00
static int fimc_link_setup ( struct media_entity * entity ,
const struct media_pad * local ,
const struct media_pad * remote , u32 flags )
{
2011-08-25 03:35:30 +04:00
struct v4l2_subdev * sd = media_entity_to_v4l2_subdev ( entity ) ;
struct fimc_dev * fimc = v4l2_get_subdevdata ( sd ) ;
2013-05-31 18:37:19 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
struct v4l2_subdev * sensor ;
2011-08-25 03:35:30 +04:00
2015-05-08 04:12:32 +03:00
if ( ! is_media_entity_v4l2_subdev ( remote - > entity ) )
2011-08-25 03:35:30 +04:00
return - EINVAL ;
2011-08-25 02:28:18 +04:00
if ( WARN_ON ( fimc = = NULL ) )
return 0 ;
dbg ( " %s --> %s, flags: 0x%x. input: 0x%x " ,
local - > entity - > name , remote - > entity - > name , flags ,
fimc - > vid_cap . input ) ;
2013-05-31 18:37:19 +04:00
if ( ! ( flags & MEDIA_LNK_FL_ENABLED ) ) {
fimc - > vid_cap . input = 0 ;
2011-08-25 02:28:18 +04:00
return 0 ;
}
2013-05-31 18:37:19 +04:00
if ( vc - > input ! = 0 )
return - EBUSY ;
vc - > input = sd - > grp_id ;
2020-07-31 02:01:11 +03:00
if ( vc - > user_subdev_api )
2013-05-31 18:37:19 +04:00
return 0 ;
/* Inherit V4L2 controls from the image sensor subdev. */
sensor = fimc_find_remote_sensor ( & vc - > subdev . entity ) ;
if ( sensor = = NULL )
return 0 ;
return v4l2_ctrl_add_handler ( & vc - > ctx - > ctrls . handler ,
2018-05-21 11:54:36 +03:00
sensor - > ctrl_handler , NULL , true ) ;
2011-08-25 02:28:18 +04:00
}
2011-08-25 03:35:30 +04:00
static const struct media_entity_operations fimc_sd_media_ops = {
2011-08-25 02:28:18 +04:00
. link_setup = fimc_link_setup ,
} ;
2011-06-10 22:36:58 +04:00
/**
* fimc_sensor_notify - v4l2_device notification from a sensor subdev
* @ sd : pointer to a subdev generating the notification
* @ notification : the notification type , must be S5P_FIMC_TX_END_NOTIFY
* @ arg : pointer to an u32 type integer that stores the frame payload value
*
* The End Of Frame notification sent by sensor subdev in its still capture
* mode . If there is only a single VSYNC generated by the sensor at the
* beginning of a frame transmission , FIMC does not issue the LastIrq
* ( end of frame ) interrupt . And this notification is used to complete the
* frame capture and returning a buffer to user - space . Subdev drivers should
* call this notification from their last ' End of frame capture ' interrupt .
*/
void fimc_sensor_notify ( struct v4l2_subdev * sd , unsigned int notification ,
void * arg )
{
2013-04-09 18:11:58 +04:00
struct fimc_source_info * si ;
2011-06-10 22:36:58 +04:00
struct fimc_vid_buffer * buf ;
struct fimc_md * fmd ;
struct fimc_dev * fimc ;
unsigned long flags ;
if ( sd = = NULL )
return ;
2013-04-09 18:11:58 +04:00
si = v4l2_get_subdev_hostdata ( sd ) ;
2011-06-10 22:36:58 +04:00
fmd = entity_to_fimc_mdev ( & sd - > entity ) ;
spin_lock_irqsave ( & fmd - > slock , flags ) ;
2013-04-09 18:11:58 +04:00
fimc = si ? source_to_sensor_info ( si ) - > host : NULL ;
2011-06-10 22:36:58 +04:00
if ( fimc & & arg & & notification = = S5P_FIMC_TX_END_NOTIFY & &
test_bit ( ST_CAPT_PEND , & fimc - > state ) ) {
unsigned long irq_flags ;
spin_lock_irqsave ( & fimc - > slock , irq_flags ) ;
if ( ! list_empty ( & fimc - > vid_cap . active_buf_q ) ) {
buf = list_entry ( fimc - > vid_cap . active_buf_q . next ,
struct fimc_vid_buffer , list ) ;
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 16:30:30 +03:00
vb2_set_plane_payload ( & buf - > vb . vb2_buf , 0 ,
* ( ( u32 * ) arg ) ) ;
2011-06-10 22:36:58 +04:00
}
2012-05-08 22:51:24 +04:00
fimc_capture_irq_handler ( fimc , 1 ) ;
2011-06-10 22:36:58 +04:00
fimc_deactivate_capture ( fimc ) ;
spin_unlock_irqrestore ( & fimc - > slock , irq_flags ) ;
}
spin_unlock_irqrestore ( & fmd - > slock , flags ) ;
}
2011-08-25 03:35:30 +04:00
static int fimc_subdev_enum_mbus_code ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2011-08-25 03:35:30 +04:00
struct v4l2_subdev_mbus_code_enum * code )
{
struct fimc_fmt * fmt ;
fmt = fimc_find_format ( NULL , NULL , FMT_FLAGS_CAM , code - > index ) ;
if ( ! fmt )
return - EINVAL ;
code - > code = fmt - > mbus_code ;
return 0 ;
}
static int fimc_subdev_get_fmt ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2011-08-25 03:35:30 +04:00
struct v4l2_subdev_format * fmt )
{
struct fimc_dev * fimc = v4l2_get_subdevdata ( sd ) ;
struct fimc_ctx * ctx = fimc - > vid_cap . ctx ;
2013-03-20 17:44:39 +04:00
struct fimc_frame * ff = & ctx - > s_frame ;
2011-08-25 03:35:30 +04:00
struct v4l2_mbus_framefmt * mf ;
if ( fmt - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
mf = v4l2_subdev_get_try_format ( sd , sd_state , fmt - > pad ) ;
2011-08-25 03:35:30 +04:00
fmt - > format = * mf ;
return 0 ;
}
2013-03-20 17:44:39 +04:00
mf = & fmt - > format ;
2011-08-25 03:35:30 +04:00
mutex_lock ( & fimc - > lock ) ;
2013-03-20 17:44:39 +04:00
switch ( fmt - > pad ) {
case FIMC_SD_PAD_SOURCE :
if ( ! WARN_ON ( ff - > fmt = = NULL ) )
mf - > code = ff - > fmt - > mbus_code ;
/* Sink pads crop rectangle size */
mf - > width = ff - > width ;
mf - > height = ff - > height ;
break ;
case FIMC_SD_PAD_SINK_FIFO :
* mf = fimc - > vid_cap . wb_fmt ;
break ;
case FIMC_SD_PAD_SINK_CAM :
default :
* mf = fimc - > vid_cap . ci_fmt ;
break ;
}
2011-08-25 03:35:30 +04:00
mutex_unlock ( & fimc - > lock ) ;
2013-03-20 17:44:39 +04:00
mf - > colorspace = V4L2_COLORSPACE_JPEG ;
2011-08-25 03:35:30 +04:00
return 0 ;
}
static int fimc_subdev_set_fmt ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2011-08-25 03:35:30 +04:00
struct v4l2_subdev_format * fmt )
{
struct fimc_dev * fimc = v4l2_get_subdevdata ( sd ) ;
struct v4l2_mbus_framefmt * mf = & fmt - > format ;
2013-03-20 17:44:39 +04:00
struct fimc_vid_cap * vc = & fimc - > vid_cap ;
struct fimc_ctx * ctx = vc - > ctx ;
2011-08-25 03:35:30 +04:00
struct fimc_frame * ff ;
struct fimc_fmt * ffmt ;
dbg ( " pad%d: code: 0x%x, %dx%d " ,
fmt - > pad , mf - > code , mf - > width , mf - > height ) ;
2013-03-20 17:44:39 +04:00
if ( fmt - > pad = = FIMC_SD_PAD_SOURCE & & vb2_is_busy ( & vc - > vbq ) )
2011-08-25 03:35:30 +04:00
return - EBUSY ;
mutex_lock ( & fimc - > lock ) ;
ffmt = fimc_capture_try_format ( ctx , & mf - > width , & mf - > height ,
& mf - > code , NULL , fmt - > pad ) ;
mutex_unlock ( & fimc - > lock ) ;
mf - > colorspace = V4L2_COLORSPACE_JPEG ;
if ( fmt - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
mf = v4l2_subdev_get_try_format ( sd , sd_state , fmt - > pad ) ;
2011-08-25 03:35:30 +04:00
* mf = fmt - > format ;
return 0 ;
}
2012-12-05 20:52:00 +04:00
/* There must be a bug in the driver if this happens */
if ( WARN_ON ( ffmt = = NULL ) )
return - EINVAL ;
2011-12-01 21:02:24 +04:00
/* Update RGB Alpha control state and value range */
fimc_alpha_ctrl_update ( ctx ) ;
2012-09-24 18:08:45 +04:00
fimc_capture_mark_jpeg_xfer ( ctx , ffmt - > color ) ;
2013-03-20 17:44:39 +04:00
if ( fmt - > pad = = FIMC_SD_PAD_SOURCE ) {
ff = & ctx - > d_frame ;
/* Sink pads crop rectangle size */
mf - > width = ctx - > s_frame . width ;
mf - > height = ctx - > s_frame . height ;
} else {
ff = & ctx - > s_frame ;
}
2011-08-25 03:35:30 +04:00
mutex_lock ( & fimc - > lock ) ;
set_frame_bounds ( ff , mf - > width , mf - > height ) ;
2013-03-20 17:44:39 +04:00
if ( fmt - > pad = = FIMC_SD_PAD_SINK_FIFO )
vc - > wb_fmt = * mf ;
else if ( fmt - > pad = = FIMC_SD_PAD_SINK_CAM )
vc - > ci_fmt = * mf ;
2011-08-25 03:35:30 +04:00
ff - > fmt = ffmt ;
/* Reset the crop rectangle if required. */
2012-04-30 00:46:03 +04:00
if ( ! ( fmt - > pad = = FIMC_SD_PAD_SOURCE & & ( ctx - > state & FIMC_COMPOSE ) ) )
2011-08-25 03:35:30 +04:00
set_frame_crop ( ff , 0 , 0 , mf - > width , mf - > height ) ;
2013-03-20 17:44:39 +04:00
if ( fmt - > pad ! = FIMC_SD_PAD_SOURCE )
2012-04-30 00:46:03 +04:00
ctx - > state & = ~ FIMC_COMPOSE ;
2013-03-20 17:44:39 +04:00
2011-08-25 03:35:30 +04:00
mutex_unlock ( & fimc - > lock ) ;
return 0 ;
}
2012-04-30 00:46:03 +04:00
static int fimc_subdev_get_selection ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2012-04-30 00:46:03 +04:00
struct v4l2_subdev_selection * sel )
2011-08-25 03:35:30 +04:00
{
struct fimc_dev * fimc = v4l2_get_subdevdata ( sd ) ;
struct fimc_ctx * ctx = fimc - > vid_cap . ctx ;
2012-04-30 00:46:03 +04:00
struct fimc_frame * f = & ctx - > s_frame ;
struct v4l2_rect * r = & sel - > r ;
struct v4l2_rect * try_sel ;
2013-03-20 17:44:39 +04:00
if ( sel - > pad = = FIMC_SD_PAD_SOURCE )
2012-04-30 00:46:03 +04:00
return - EINVAL ;
mutex_lock ( & fimc - > lock ) ;
2011-08-25 03:35:30 +04:00
2012-04-30 00:46:03 +04:00
switch ( sel - > target ) {
2012-05-18 16:31:18 +04:00
case V4L2_SEL_TGT_COMPOSE_BOUNDS :
2012-04-30 00:46:03 +04:00
f = & ctx - > d_frame ;
2020-07-25 01:10:14 +03:00
fallthrough ;
2012-05-18 16:31:18 +04:00
case V4L2_SEL_TGT_CROP_BOUNDS :
2012-04-30 00:46:03 +04:00
r - > width = f - > o_width ;
r - > height = f - > o_height ;
r - > left = 0 ;
r - > top = 0 ;
mutex_unlock ( & fimc - > lock ) ;
2011-08-25 03:35:30 +04:00
return 0 ;
2012-04-30 00:46:03 +04:00
2012-05-18 16:31:18 +04:00
case V4L2_SEL_TGT_CROP :
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
try_sel = v4l2_subdev_get_try_crop ( sd , sd_state , sel - > pad ) ;
2012-04-30 00:46:03 +04:00
break ;
2012-05-18 16:31:18 +04:00
case V4L2_SEL_TGT_COMPOSE :
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
try_sel = v4l2_subdev_get_try_compose ( sd , sd_state , sel - > pad ) ;
2012-04-30 00:46:03 +04:00
f = & ctx - > d_frame ;
break ;
default :
mutex_unlock ( & fimc - > lock ) ;
return - EINVAL ;
2011-08-25 03:35:30 +04:00
}
2012-04-30 00:46:03 +04:00
if ( sel - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
sel - > r = * try_sel ;
} else {
r - > left = f - > offs_h ;
r - > top = f - > offs_v ;
r - > width = f - > width ;
r - > height = f - > height ;
}
2011-08-25 03:35:30 +04:00
2012-04-30 00:46:03 +04:00
dbg ( " target %#x: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d " ,
sel - > pad , r - > left , r - > top , r - > width , r - > height ,
f - > f_width , f - > f_height ) ;
2011-08-25 03:35:30 +04:00
2012-04-30 00:46:03 +04:00
mutex_unlock ( & fimc - > lock ) ;
2011-08-25 03:35:30 +04:00
return 0 ;
}
2012-04-30 00:46:03 +04:00
static int fimc_subdev_set_selection ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2012-04-30 00:46:03 +04:00
struct v4l2_subdev_selection * sel )
2011-08-25 03:35:30 +04:00
{
struct fimc_dev * fimc = v4l2_get_subdevdata ( sd ) ;
struct fimc_ctx * ctx = fimc - > vid_cap . ctx ;
2012-04-30 00:46:03 +04:00
struct fimc_frame * f = & ctx - > s_frame ;
struct v4l2_rect * r = & sel - > r ;
struct v4l2_rect * try_sel ;
2011-08-25 03:35:30 +04:00
unsigned long flags ;
2013-03-20 17:44:39 +04:00
if ( sel - > pad = = FIMC_SD_PAD_SOURCE )
2012-04-30 00:46:03 +04:00
return - EINVAL ;
2011-08-25 03:35:30 +04:00
mutex_lock ( & fimc - > lock ) ;
2012-05-20 18:17:12 +04:00
fimc_capture_try_selection ( ctx , r , V4L2_SEL_TGT_CROP ) ;
2011-08-25 03:35:30 +04:00
2012-04-30 00:46:03 +04:00
switch ( sel - > target ) {
2012-05-18 16:31:18 +04:00
case V4L2_SEL_TGT_CROP :
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
try_sel = v4l2_subdev_get_try_crop ( sd , sd_state , sel - > pad ) ;
2012-04-30 00:46:03 +04:00
break ;
2012-05-18 16:31:18 +04:00
case V4L2_SEL_TGT_COMPOSE :
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
try_sel = v4l2_subdev_get_try_compose ( sd , sd_state , sel - > pad ) ;
2012-04-30 00:46:03 +04:00
f = & ctx - > d_frame ;
break ;
default :
mutex_unlock ( & fimc - > lock ) ;
return - EINVAL ;
2011-08-25 03:35:30 +04:00
}
2012-04-30 00:46:03 +04:00
if ( sel - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
* try_sel = sel - > r ;
} else {
spin_lock_irqsave ( & fimc - > slock , flags ) ;
set_frame_crop ( f , r - > left , r - > top , r - > width , r - > height ) ;
set_bit ( ST_CAPT_APPLY_CFG , & fimc - > state ) ;
2012-05-18 16:31:18 +04:00
if ( sel - > target = = V4L2_SEL_TGT_COMPOSE )
2012-04-30 00:46:03 +04:00
ctx - > state | = FIMC_COMPOSE ;
2013-01-30 16:55:46 +04:00
spin_unlock_irqrestore ( & fimc - > slock , flags ) ;
2012-04-30 00:46:03 +04:00
}
2011-08-25 03:35:30 +04:00
2012-04-30 00:46:03 +04:00
dbg ( " target %#x: (%d,%d)/%dx%d " , sel - > target , r - > left , r - > top ,
2011-08-25 03:35:30 +04:00
r - > width , r - > height ) ;
mutex_unlock ( & fimc - > lock ) ;
return 0 ;
}
2016-12-12 21:03:57 +03:00
static const struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
2011-08-25 03:35:30 +04:00
. enum_mbus_code = fimc_subdev_enum_mbus_code ,
2012-04-30 00:46:03 +04:00
. get_selection = fimc_subdev_get_selection ,
. set_selection = fimc_subdev_set_selection ,
2011-08-25 03:35:30 +04:00
. get_fmt = fimc_subdev_get_fmt ,
. set_fmt = fimc_subdev_set_fmt ,
} ;
2016-12-12 21:03:57 +03:00
static const struct v4l2_subdev_ops fimc_subdev_ops = {
2011-08-25 03:35:30 +04:00
. pad = & fimc_subdev_pad_ops ,
} ;
/* Set default format at the sensor and host interface */
static int fimc_capture_set_default_format ( struct fimc_dev * fimc )
{
struct v4l2_format fmt = {
. type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ,
. fmt . pix_mp = {
2013-06-18 21:56:11 +04:00
. width = FIMC_DEFAULT_WIDTH ,
. height = FIMC_DEFAULT_HEIGHT ,
2011-08-25 03:35:30 +04:00
. pixelformat = V4L2_PIX_FMT_YUYV ,
. field = V4L2_FIELD_NONE ,
. colorspace = V4L2_COLORSPACE_JPEG ,
} ,
} ;
2012-12-06 17:26:19 +04:00
return __fimc_capture_set_format ( fimc , & fmt ) ;
2011-08-25 03:35:30 +04:00
}
2010-12-08 20:05:08 +03:00
/* fimc->lock must be already initialized */
2012-04-21 01:57:25 +04:00
static int fimc_register_capture_device ( struct fimc_dev * fimc ,
2011-06-10 22:36:48 +04:00
struct v4l2_device * v4l2_dev )
2010-10-07 17:06:16 +04:00
{
2013-05-31 18:37:18 +04:00
struct video_device * vfd = & fimc - > vid_cap . ve . vdev ;
2013-03-25 23:36:35 +04:00
struct vb2_queue * q = & fimc - > vid_cap . vbq ;
2010-10-07 17:06:16 +04:00
struct fimc_ctx * ctx ;
2013-03-25 23:36:35 +04:00
struct fimc_vid_cap * vid_cap ;
2013-06-18 21:56:11 +04:00
struct fimc_fmt * fmt ;
2011-06-10 22:36:48 +04:00
int ret = - ENOMEM ;
2010-10-07 17:06:16 +04:00
2012-08-17 10:28:27 +04:00
ctx = kzalloc ( sizeof ( * ctx ) , GFP_KERNEL ) ;
2010-10-07 17:06:16 +04:00
if ( ! ctx )
return - ENOMEM ;
ctx - > fimc_dev = fimc ;
2012-04-26 13:26:29 +04:00
ctx - > in_path = FIMC_IO_CAMERA ;
ctx - > out_path = FIMC_IO_DMA ;
2010-10-07 17:06:16 +04:00
ctx - > state = FIMC_CTX_CAP ;
2011-08-25 03:35:30 +04:00
ctx - > s_frame . fmt = fimc_find_format ( NULL , NULL , FMT_FLAGS_CAM , 0 ) ;
2012-04-21 01:57:25 +04:00
ctx - > d_frame . fmt = ctx - > s_frame . fmt ;
2010-10-07 17:06:16 +04:00
2012-07-26 14:15:42 +04:00
memset ( vfd , 0 , sizeof ( * vfd ) ) ;
2012-04-21 01:57:25 +04:00
snprintf ( vfd - > name , sizeof ( vfd - > name ) , " fimc.%d.capture " , fimc - > id ) ;
2010-10-07 17:06:16 +04:00
vfd - > fops = & fimc_capture_fops ;
vfd - > ioctl_ops = & fimc_capture_ioctl_ops ;
2011-07-27 01:08:21 +04:00
vfd - > v4l2_dev = v4l2_dev ;
2010-10-07 17:06:16 +04:00
vfd - > minor = - 1 ;
2012-07-26 14:15:42 +04:00
vfd - > release = video_device_release_empty ;
2013-03-25 23:36:35 +04:00
vfd - > queue = q ;
2010-12-01 16:25:18 +03:00
vfd - > lock = & fimc - > lock ;
2019-06-04 10:06:24 +03:00
vfd - > device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE ;
2012-06-27 16:56:17 +04:00
2010-10-07 17:06:16 +04:00
video_set_drvdata ( vfd , fimc ) ;
vid_cap = & fimc - > vid_cap ;
vid_cap - > active_buf_cnt = 0 ;
2013-03-25 23:36:35 +04:00
vid_cap - > reqbufs_count = 0 ;
vid_cap - > ctx = ctx ;
2010-10-07 17:06:16 +04:00
INIT_LIST_HEAD ( & vid_cap - > pending_buf_q ) ;
INIT_LIST_HEAD ( & vid_cap - > active_buf_q ) ;
2010-12-01 16:14:59 +03:00
memset ( q , 0 , sizeof ( * q ) ) ;
2010-12-08 20:05:08 +03:00
q - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ;
2012-06-14 17:37:49 +04:00
q - > io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF ;
2013-03-25 23:36:35 +04:00
q - > drv_priv = ctx ;
2010-12-01 16:14:59 +03:00
q - > ops = & fimc_capture_qops ;
q - > mem_ops = & vb2_dma_contig_memops ;
q - > buf_struct_size = sizeof ( struct fimc_vid_buffer ) ;
2014-02-26 02:12:19 +04:00
q - > timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC ;
2013-03-25 23:36:35 +04:00
q - > lock = & fimc - > lock ;
2016-02-16 12:30:19 +03:00
q - > dev = & fimc - > pdev - > dev ;
2010-12-01 16:14:59 +03:00
2012-10-19 15:24:18 +04:00
ret = vb2_queue_init ( q ) ;
if ( ret )
2013-05-31 18:37:19 +04:00
goto err_free_ctx ;
2010-10-07 17:06:16 +04:00
2013-06-18 21:56:11 +04:00
/* Default format configuration */
fmt = fimc_find_format ( NULL , NULL , FMT_FLAGS_CAM , 0 ) ;
vid_cap - > ci_fmt . width = FIMC_DEFAULT_WIDTH ;
vid_cap - > ci_fmt . height = FIMC_DEFAULT_HEIGHT ;
vid_cap - > ci_fmt . code = fmt - > mbus_code ;
ctx - > s_frame . width = FIMC_DEFAULT_WIDTH ;
ctx - > s_frame . height = FIMC_DEFAULT_HEIGHT ;
ctx - > s_frame . fmt = fmt ;
fmt = fimc_find_format ( NULL , NULL , FMT_FLAGS_WRITEBACK , 0 ) ;
vid_cap - > wb_fmt = vid_cap - > ci_fmt ;
vid_cap - > wb_fmt . code = fmt - > mbus_code ;
2012-04-21 01:57:25 +04:00
vid_cap - > vd_pad . flags = MEDIA_PAD_FL_SINK ;
2016-09-01 14:47:05 +03:00
vfd - > entity . function = MEDIA_ENT_F_PROC_VIDEO_SCALER ;
2015-12-11 12:44:40 +03:00
ret = media_entity_pads_init ( & vfd - > entity , 1 , & vid_cap - > vd_pad ) ;
2011-07-27 01:08:21 +04:00
if ( ret )
2013-05-31 18:37:19 +04:00
goto err_free_ctx ;
ret = fimc_ctrls_create ( ctx ) ;
if ( ret )
goto err_me_cleanup ;
2012-04-21 01:57:25 +04:00
2020-02-03 14:41:18 +03:00
ret = video_register_device ( vfd , VFL_TYPE_VIDEO , - 1 ) ;
2011-08-25 03:35:30 +04:00
if ( ret )
2013-05-31 18:37:19 +04:00
goto err_ctrl_free ;
2012-04-21 01:57:25 +04:00
v4l2_info ( v4l2_dev , " Registered %s as /dev/%s \n " ,
vfd - > name , video_device_node_name ( vfd ) ) ;
2011-07-27 01:08:21 +04:00
2012-04-02 13:41:22 +04:00
vfd - > ctrl_handler = & ctx - > ctrls . handler ;
2010-10-07 17:06:16 +04:00
return 0 ;
2013-05-31 18:37:19 +04:00
err_ctrl_free :
fimc_ctrls_delete ( ctx ) ;
err_me_cleanup :
2011-08-25 03:35:30 +04:00
media_entity_cleanup ( & vfd - > entity ) ;
2013-05-31 18:37:19 +04:00
err_free_ctx :
2011-06-02 13:18:34 +04:00
kfree ( ctx ) ;
2010-10-07 17:06:16 +04:00
return ret ;
}
2012-04-21 01:57:25 +04:00
static int fimc_capture_subdev_registered ( struct v4l2_subdev * sd )
2010-10-07 17:06:16 +04:00
{
2012-04-21 01:57:25 +04:00
struct fimc_dev * fimc = v4l2_get_subdevdata ( sd ) ;
int ret ;
2010-10-07 17:06:16 +04:00
2012-07-26 14:59:11 +04:00
if ( fimc = = NULL )
return - ENXIO ;
2012-04-21 01:57:25 +04:00
ret = fimc_register_m2m_device ( fimc , sd - > v4l2_dev ) ;
if ( ret )
return ret ;
2013-05-31 18:37:22 +04:00
fimc - > vid_cap . ve . pipe = v4l2_get_subdev_hostdata ( sd ) ;
2012-11-22 13:17:19 +04:00
2012-04-21 01:57:25 +04:00
ret = fimc_register_capture_device ( fimc , sd - > v4l2_dev ) ;
2012-11-22 13:17:19 +04:00
if ( ret ) {
2012-04-21 01:57:25 +04:00
fimc_unregister_m2m_device ( fimc ) ;
2013-05-31 18:37:22 +04:00
fimc - > vid_cap . ve . pipe = NULL ;
2012-11-22 13:17:19 +04:00
}
2012-04-21 01:57:25 +04:00
return ret ;
}
static void fimc_capture_subdev_unregistered ( struct v4l2_subdev * sd )
{
struct fimc_dev * fimc = v4l2_get_subdevdata ( sd ) ;
2013-05-31 18:37:18 +04:00
struct video_device * vdev ;
2012-04-21 01:57:25 +04:00
if ( fimc = = NULL )
return ;
2013-05-31 18:37:25 +04:00
mutex_lock ( & fimc - > lock ) ;
2012-04-21 01:57:25 +04:00
fimc_unregister_m2m_device ( fimc ) ;
2013-05-31 18:37:18 +04:00
vdev = & fimc - > vid_cap . ve . vdev ;
2012-04-21 01:57:25 +04:00
2013-05-31 18:37:18 +04:00
if ( video_is_registered ( vdev ) ) {
video_unregister_device ( vdev ) ;
media_entity_cleanup ( & vdev - > entity ) ;
2013-05-31 18:37:19 +04:00
fimc_ctrls_delete ( fimc - > vid_cap . ctx ) ;
2013-05-31 18:37:22 +04:00
fimc - > vid_cap . ve . pipe = NULL ;
2011-07-27 01:08:21 +04:00
}
kfree ( fimc - > vid_cap . ctx ) ;
2011-08-26 22:40:36 +04:00
fimc - > vid_cap . ctx = NULL ;
2013-05-31 18:37:25 +04:00
mutex_unlock ( & fimc - > lock ) ;
2010-10-07 17:06:16 +04:00
}
2012-04-21 01:57:25 +04:00
static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = {
. registered = fimc_capture_subdev_registered ,
. unregistered = fimc_capture_subdev_unregistered ,
} ;
int fimc_initialize_capture_subdev ( struct fimc_dev * fimc )
{
struct v4l2_subdev * sd = & fimc - > vid_cap . subdev ;
int ret ;
v4l2_subdev_init ( sd , & fimc_subdev_ops ) ;
2013-04-18 15:49:54 +04:00
sd - > flags | = V4L2_SUBDEV_FL_HAS_DEVNODE ;
2013-03-26 15:22:21 +04:00
snprintf ( sd - > name , sizeof ( sd - > name ) , " FIMC.%d " , fimc - > id ) ;
2012-04-21 01:57:25 +04:00
2013-03-20 17:44:39 +04:00
fimc - > vid_cap . sd_pads [ FIMC_SD_PAD_SINK_CAM ] . flags = MEDIA_PAD_FL_SINK ;
fimc - > vid_cap . sd_pads [ FIMC_SD_PAD_SINK_FIFO ] . flags = MEDIA_PAD_FL_SINK ;
2012-04-21 01:57:25 +04:00
fimc - > vid_cap . sd_pads [ FIMC_SD_PAD_SOURCE ] . flags = MEDIA_PAD_FL_SOURCE ;
2015-12-11 12:44:40 +03:00
ret = media_entity_pads_init ( & sd - > entity , FIMC_SD_PADS_NUM ,
2015-08-06 15:25:57 +03:00
fimc - > vid_cap . sd_pads ) ;
2012-04-21 01:57:25 +04:00
if ( ret )
return ret ;
sd - > entity . ops = & fimc_sd_media_ops ;
2020-07-31 02:01:07 +03:00
sd - > entity . function = MEDIA_ENT_F_PROC_VIDEO_SCALER ;
2012-04-21 01:57:25 +04:00
sd - > internal_ops = & fimc_capture_sd_internal_ops ;
v4l2_set_subdevdata ( sd , fimc ) ;
return 0 ;
}
void fimc_unregister_capture_subdev ( struct fimc_dev * fimc )
{
struct v4l2_subdev * sd = & fimc - > vid_cap . subdev ;
v4l2_device_unregister_subdev ( sd ) ;
media_entity_cleanup ( & sd - > entity ) ;
v4l2_set_subdevdata ( sd , NULL ) ;
}