2019-05-20 10:19:09 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2008-08-08 19:43:59 +04:00
/*
saa6752hs - i2c - driver for the saa6752hs by Philips
Copyright ( C ) 2004 Andrew de Quincey
AC - 3 support :
Copyright ( C ) 2008 Hans Verkuil < hverkuil @ xs4all . nl >
*/
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/poll.h>
# include <linux/i2c.h>
# include <linux/types.h>
2006-01-09 20:53:26 +03:00
# include <linux/videodev2.h>
2013-12-14 15:28:30 +04:00
# include <linux/init.h>
# include <linux/crc32.h>
2009-01-14 12:54:38 +03:00
# include <media/v4l2-device.h>
2013-06-10 11:51:42 +04:00
# include <media/v4l2-ctrls.h>
2006-01-09 20:53:26 +03:00
# include <media/v4l2-common.h>
2005-04-17 02:20:36 +04:00
# define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
# define MPEG_VIDEO_MAX_BITRATE_MAX 27000
# define MPEG_TOTAL_TARGET_BITRATE_MAX 27000
# define MPEG_PID_MAX ((1 << 14) - 1)
MODULE_DESCRIPTION ( " device driver for saa6752hs MPEG2 encoder " ) ;
MODULE_AUTHOR ( " Andrew de Quincey " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-05-06 03:15:52 +04:00
enum saa6752hs_videoformat {
SAA6752HS_VF_D1 = 0 , /* standard D1 video format: 720x576 */
SAA6752HS_VF_2_3_D1 = 1 , /* 2/3D1 video format: 480x576 */
SAA6752HS_VF_1_2_D1 = 2 , /* 1/2D1 video format: 352x576 */
SAA6752HS_VF_SIF = 3 , /* SIF video format: 352x288 */
SAA6752HS_VF_UNKNOWN ,
} ;
2006-06-18 23:40:10 +04:00
struct saa6752hs_mpeg_params {
/* transport streams */
__u16 ts_pid_pmt ;
__u16 ts_pid_audio ;
__u16 ts_pid_video ;
__u16 ts_pid_pcr ;
/* audio */
2008-08-08 19:43:59 +04:00
enum v4l2_mpeg_audio_encoding au_encoding ;
enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate ;
enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate ;
2006-06-18 23:40:10 +04:00
/* video */
enum v4l2_mpeg_video_aspect vi_aspect ;
enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode ;
2018-01-04 21:08:56 +03:00
__u32 vi_bitrate ;
__u32 vi_bitrate_peak ;
2006-06-18 23:40:10 +04:00
} ;
2005-05-06 03:15:52 +04:00
static const struct v4l2_format v4l2_format_table [ ] =
{
2005-06-24 09:05:09 +04:00
[ SAA6752HS_VF_D1 ] =
{ . fmt = { . pix = { . width = 720 , . height = 576 } } } ,
[ SAA6752HS_VF_2_3_D1 ] =
{ . fmt = { . pix = { . width = 480 , . height = 576 } } } ,
[ SAA6752HS_VF_1_2_D1 ] =
{ . fmt = { . pix = { . width = 352 , . height = 576 } } } ,
[ SAA6752HS_VF_SIF ] =
{ . fmt = { . pix = { . width = 352 , . height = 288 } } } ,
[ SAA6752HS_VF_UNKNOWN ] =
{ . fmt = { . pix = { . width = 0 , . height = 0 } } } ,
2005-05-06 03:15:52 +04:00
} ;
2005-04-17 02:20:36 +04:00
struct saa6752hs_state {
2009-01-14 12:54:38 +03:00
struct v4l2_subdev sd ;
2013-06-10 11:51:42 +04:00
struct v4l2_ctrl_handler hdl ;
struct { /* video bitrate mode control cluster */
struct v4l2_ctrl * video_bitrate_mode ;
struct v4l2_ctrl * video_bitrate ;
struct v4l2_ctrl * video_bitrate_peak ;
} ;
2018-01-04 21:08:56 +03:00
u32 revision ;
int has_ac3 ;
2006-06-18 23:40:10 +04:00
struct saa6752hs_mpeg_params params ;
2005-05-06 03:15:52 +04:00
enum saa6752hs_videoformat video_format ;
2005-11-09 08:36:45 +03:00
v4l2_std_id standard ;
2005-04-17 02:20:36 +04:00
} ;
enum saa6752hs_command {
SAA6752HS_COMMAND_RESET = 0 ,
2006-06-20 07:30:57 +04:00
SAA6752HS_COMMAND_STOP = 1 ,
SAA6752HS_COMMAND_START = 2 ,
SAA6752HS_COMMAND_PAUSE = 3 ,
SAA6752HS_COMMAND_RECONFIGURE = 4 ,
SAA6752HS_COMMAND_SLEEP = 5 ,
2005-04-17 02:20:36 +04:00
SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6 ,
SAA6752HS_COMMAND_MAX
} ;
2009-01-14 12:54:38 +03:00
static inline struct saa6752hs_state * to_state ( struct v4l2_subdev * sd )
{
return container_of ( sd , struct saa6752hs_state , sd ) ;
}
2005-04-17 02:20:36 +04:00
/* ---------------------------------------------------------------------- */
2013-12-14 15:28:30 +04:00
static const u8 PAT [ ] = {
2005-11-09 08:36:45 +03:00
0xc2 , /* i2c register */
0x00 , /* table number for encoder */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x47 , /* sync */
0x40 , 0x00 , /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
0x10 , /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , /* PSI pointer to start of table */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , /* tid(0) */
0xb0 , 0x0d , /* section_syntax_indicator(1), section_length(13) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x01 , /* transport_stream_id(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xc1 , /* version_number(0), current_next_indicator(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x00 , /* section_number(0), last_section_number(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x01 , /* program_number(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xe0 , 0x00 , /* PMT PID */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x00 , 0x00 , 0x00 /* CRC32 */
2005-04-17 02:20:36 +04:00
} ;
2013-12-14 15:28:30 +04:00
static const u8 PMT [ ] = {
2005-11-09 08:36:45 +03:00
0xc2 , /* i2c register */
0x01 , /* table number for encoder */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x47 , /* sync */
0x40 , 0x00 , /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
0x10 , /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , /* PSI pointer to start of table */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x02 , /* tid(2) */
0xb0 , 0x17 , /* section_syntax_indicator(1), section_length(23) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x01 , /* program_number(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xc1 , /* version_number(0), current_next_indicator(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x00 , /* section_number(0), last_section_number(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xe0 , 0x00 , /* PCR_PID */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xf0 , 0x00 , /* program_info_length(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x02 , 0xe0 , 0x00 , 0xf0 , 0x00 , /* video stream type(2), pid */
0x04 , 0xe0 , 0x00 , 0xf0 , 0x00 , /* audio stream type(4), pid */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x00 , 0x00 , 0x00 /* CRC32 */
2005-04-17 02:20:36 +04:00
} ;
2013-12-14 15:28:30 +04:00
static const u8 PMT_AC3 [ ] = {
2008-08-08 20:27:16 +04:00
0xc2 , /* i2c register */
0x01 , /* table number for encoder(1) */
0x47 , /* sync */
0x40 , /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */
0x10 , /* PMT PID (0x0010) */
0x10 , /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
0x00 , /* PSI pointer to start of table */
0x02 , /* TID (2) */
0xb0 , 0x1a , /* section_syntax_indicator(1), section_length(26) */
0x00 , 0x01 , /* program_number(1) */
0xc1 , /* version_number(0), current_next_indicator(1) */
0x00 , 0x00 , /* section_number(0), last_section_number(0) */
0xe1 , 0x04 , /* PCR_PID (0x0104) */
0xf0 , 0x00 , /* program_info_length(0) */
0x02 , 0xe1 , 0x00 , 0xf0 , 0x00 , /* video stream type(2), pid */
0x06 , 0xe1 , 0x03 , 0xf0 , 0x03 , /* audio stream type(6), pid */
0x6a , /* AC3 */
0x01 , /* Descriptor_length(1) */
0x00 , /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */
0xED , 0xDE , 0x2D , 0xF3 /* CRC32 BE */
} ;
2013-12-14 15:28:30 +04:00
static const struct saa6752hs_mpeg_params param_defaults =
2006-06-18 23:40:10 +04:00
{
. ts_pid_pmt = 16 ,
. ts_pid_video = 260 ,
. ts_pid_audio = 256 ,
. ts_pid_pcr = 259 ,
. vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3 ,
. vi_bitrate = 4000 ,
. vi_bitrate_peak = 6000 ,
. vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ,
2008-08-08 19:43:59 +04:00
. au_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2 ,
2006-06-18 23:40:10 +04:00
. au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K ,
2008-08-08 20:27:16 +04:00
. au_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_256K ,
2006-06-18 23:40:10 +04:00
} ;
2005-04-17 02:20:36 +04:00
/* ---------------------------------------------------------------------- */
2008-09-06 14:00:24 +04:00
static int saa6752hs_chip_command ( struct i2c_client * client ,
2005-04-17 02:20:36 +04:00
enum saa6752hs_command command )
{
unsigned char buf [ 3 ] ;
unsigned long timeout ;
int status = 0 ;
2005-11-09 08:36:45 +03:00
/* execute the command */
2005-04-17 02:20:36 +04:00
switch ( command ) {
2005-11-09 08:37:43 +03:00
case SAA6752HS_COMMAND_RESET :
buf [ 0 ] = 0x00 ;
2005-04-17 02:20:36 +04:00
break ;
case SAA6752HS_COMMAND_STOP :
2005-11-09 08:37:43 +03:00
buf [ 0 ] = 0x03 ;
2005-04-17 02:20:36 +04:00
break ;
case SAA6752HS_COMMAND_START :
2005-11-09 08:37:43 +03:00
buf [ 0 ] = 0x02 ;
2005-04-17 02:20:36 +04:00
break ;
case SAA6752HS_COMMAND_PAUSE :
2005-11-09 08:37:43 +03:00
buf [ 0 ] = 0x04 ;
2005-04-17 02:20:36 +04:00
break ;
case SAA6752HS_COMMAND_RECONFIGURE :
buf [ 0 ] = 0x05 ;
break ;
2005-11-09 08:37:43 +03:00
case SAA6752HS_COMMAND_SLEEP :
buf [ 0 ] = 0x06 ;
2005-04-17 02:20:36 +04:00
break ;
2005-11-09 08:37:43 +03:00
case SAA6752HS_COMMAND_RECONFIGURE_FORCE :
2005-04-17 02:20:36 +04:00
buf [ 0 ] = 0x07 ;
break ;
default :
return - EINVAL ;
}
2005-11-09 08:37:43 +03:00
/* set it and wait for it to be so */
2005-04-17 02:20:36 +04:00
i2c_master_send ( client , buf , 1 ) ;
timeout = jiffies + HZ * 3 ;
for ( ; ; ) {
2005-11-09 08:36:45 +03:00
/* get the current status */
2005-04-17 02:20:36 +04:00
buf [ 0 ] = 0x10 ;
2005-11-09 08:37:43 +03:00
i2c_master_send ( client , buf , 1 ) ;
2005-04-17 02:20:36 +04:00
i2c_master_recv ( client , buf , 1 ) ;
if ( ! ( buf [ 0 ] & 0x20 ) )
break ;
if ( time_after ( jiffies , timeout ) ) {
status = - ETIMEDOUT ;
break ;
}
msleep ( 10 ) ;
}
2005-11-09 08:36:45 +03:00
/* delay a bit to let encoder settle */
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
2005-11-09 08:37:43 +03:00
return status ;
2005-04-17 02:20:36 +04:00
}
2008-09-06 14:00:24 +04:00
static inline void set_reg8 ( struct i2c_client * client , uint8_t reg , uint8_t val )
{
u8 buf [ 2 ] ;
buf [ 0 ] = reg ;
buf [ 1 ] = val ;
i2c_master_send ( client , buf , 2 ) ;
}
static inline void set_reg16 ( struct i2c_client * client , uint8_t reg , uint16_t val )
{
u8 buf [ 3 ] ;
buf [ 0 ] = reg ;
buf [ 1 ] = val > > 8 ;
buf [ 2 ] = val & 0xff ;
i2c_master_send ( client , buf , 3 ) ;
}
static int saa6752hs_set_bitrate ( struct i2c_client * client ,
2008-08-08 19:43:59 +04:00
struct saa6752hs_state * h )
2005-04-17 02:20:36 +04:00
{
2008-08-08 19:43:59 +04:00
struct saa6752hs_mpeg_params * params = & h - > params ;
2006-06-23 23:13:56 +04:00
int tot_bitrate ;
2008-09-06 14:00:24 +04:00
int is_384k ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* set the bitrate mode */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x71 ,
params - > vi_bitrate_mode ! = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* set the video bitrate */
2006-06-23 23:13:56 +04:00
if ( params - > vi_bitrate_mode = = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ) {
2005-11-09 08:36:45 +03:00
/* set the target bitrate */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0x80 , params - > vi_bitrate ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* set the max bitrate */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0x81 , params - > vi_bitrate_peak ) ;
2006-06-23 23:13:56 +04:00
tot_bitrate = params - > vi_bitrate_peak ;
2005-04-17 02:20:36 +04:00
} else {
2005-11-09 08:36:45 +03:00
/* set the target bitrate (no max bitrate for CBR) */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0x81 , params - > vi_bitrate ) ;
2006-06-23 23:13:56 +04:00
tot_bitrate = params - > vi_bitrate ;
2005-04-17 02:20:36 +04:00
}
2008-08-08 19:43:59 +04:00
/* set the audio encoding */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x93 ,
params - > au_encoding = = V4L2_MPEG_AUDIO_ENCODING_AC3 ) ;
2008-08-08 19:43:59 +04:00
2005-11-09 08:36:45 +03:00
/* set the audio bitrate */
2008-08-08 19:43:59 +04:00
if ( params - > au_encoding = = V4L2_MPEG_AUDIO_ENCODING_AC3 )
2008-09-06 14:00:24 +04:00
is_384k = V4L2_MPEG_AUDIO_AC3_BITRATE_384K = = params - > au_ac3_bitrate ;
2008-08-08 19:43:59 +04:00
else
2008-09-06 14:00:24 +04:00
is_384k = V4L2_MPEG_AUDIO_L2_BITRATE_384K = = params - > au_l2_bitrate ;
set_reg8 ( client , 0x94 , is_384k ) ;
tot_bitrate + = is_384k ? 384 : 256 ;
2006-06-23 23:13:56 +04:00
/* Note: the total max bitrate is determined by adding the video and audio
bitrates together and also adding an extra 768 kbit / s to stay on the
safe side . If more control should be required , then an extra MPEG control
should be added . */
tot_bitrate + = 768 ;
if ( tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX )
tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* set the total bitrate */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xb1 , tot_bitrate ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2013-06-10 11:51:42 +04:00
static int saa6752hs_try_ctrl ( struct v4l2_ctrl * ctrl )
2009-01-14 12:54:38 +03:00
{
2013-06-10 11:51:42 +04:00
struct saa6752hs_state * h =
container_of ( ctrl - > handler , struct saa6752hs_state , hdl ) ;
2009-01-14 12:54:38 +03:00
switch ( ctrl - > id ) {
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE :
2013-06-10 11:51:42 +04:00
/* peak bitrate shall be >= normal bitrate */
if ( ctrl - > val = = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR & &
h - > video_bitrate_peak - > val < h - > video_bitrate - > val )
h - > video_bitrate_peak - > val = h - > video_bitrate - > val ;
2009-01-14 12:54:38 +03:00
break ;
2005-05-06 03:15:52 +04:00
}
2009-01-14 12:54:38 +03:00
return 0 ;
2005-05-06 03:15:52 +04:00
}
2013-06-10 11:51:42 +04:00
static int saa6752hs_s_ctrl ( struct v4l2_ctrl * ctrl )
2006-06-18 23:40:10 +04:00
{
2013-06-10 11:51:42 +04:00
struct saa6752hs_state * h =
container_of ( ctrl - > handler , struct saa6752hs_state , hdl ) ;
struct saa6752hs_mpeg_params * params = & h - > params ;
2006-06-18 23:40:10 +04:00
switch ( ctrl - > id ) {
2009-01-14 12:54:38 +03:00
case V4L2_CID_MPEG_STREAM_TYPE :
break ;
case V4L2_CID_MPEG_STREAM_PID_PMT :
2013-06-10 11:51:42 +04:00
params - > ts_pid_pmt = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_STREAM_PID_AUDIO :
2013-06-10 11:51:42 +04:00
params - > ts_pid_audio = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_STREAM_PID_VIDEO :
2013-06-10 11:51:42 +04:00
params - > ts_pid_video = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_STREAM_PID_PCR :
2013-06-10 11:51:42 +04:00
params - > ts_pid_pcr = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_AUDIO_ENCODING :
2013-06-10 11:51:42 +04:00
params - > au_encoding = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE :
2013-06-10 11:51:42 +04:00
params - > au_l2_bitrate = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_AUDIO_AC3_BITRATE :
2013-06-10 11:51:42 +04:00
params - > au_ac3_bitrate = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ :
break ;
case V4L2_CID_MPEG_VIDEO_ENCODING :
break ;
case V4L2_CID_MPEG_VIDEO_ASPECT :
2013-06-10 11:51:42 +04:00
params - > vi_aspect = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE :
2013-06-10 11:51:42 +04:00
params - > vi_bitrate_mode = ctrl - > val ;
params - > vi_bitrate = h - > video_bitrate - > val / 1000 ;
params - > vi_bitrate_peak = h - > video_bitrate_peak - > val / 1000 ;
v4l2_ctrl_activate ( h - > video_bitrate_peak ,
ctrl - > val = = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ) ;
2009-01-14 12:54:38 +03:00
break ;
default :
return - EINVAL ;
2006-06-18 23:40:10 +04:00
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 12:54:38 +03:00
static int saa6752hs_init ( struct v4l2_subdev * sd , u32 leading_null_bytes )
2005-04-17 02:20:36 +04:00
{
unsigned char buf [ 9 ] , buf2 [ 4 ] ;
2009-01-14 12:54:38 +03:00
struct saa6752hs_state * h = to_state ( sd ) ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-08-08 20:27:16 +04:00
unsigned size ;
2005-04-17 02:20:36 +04:00
u32 crc ;
unsigned char localPAT [ 256 ] ;
unsigned char localPMT [ 256 ] ;
2005-11-09 08:36:45 +03:00
/* Set video format - must be done first as it resets other settings */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x41 , h - > video_format ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* Set number of lines in input signal */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x40 , ( h - > standard & V4L2_STD_525_60 ) ? 1 : 0 ) ;
2005-11-09 08:36:45 +03:00
2005-11-09 08:37:43 +03:00
/* set bitrate */
2008-08-08 19:43:59 +04:00
saa6752hs_set_bitrate ( client , h ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* Set GOP structure {3, 13} */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0x72 , 0x030d ) ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set minimum Q-scale {4} */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x82 , 0x04 ) ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set maximum Q-scale {12} */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x83 , 0x0c ) ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set Output Protocol */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0xd0 , 0x81 ) ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set video output stream format {TS} */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0xb0 , 0x05 ) ;
2005-04-17 02:20:36 +04:00
2008-08-26 20:44:40 +04:00
/* Set leading null byte for TS */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xf6 , leading_null_bytes ) ;
2008-08-26 20:44:40 +04:00
2005-04-17 02:20:36 +04:00
/* compute PAT */
memcpy ( localPAT , PAT , sizeof ( PAT ) ) ;
localPAT [ 17 ] = 0xe0 | ( ( h - > params . ts_pid_pmt > > 8 ) & 0x0f ) ;
localPAT [ 18 ] = h - > params . ts_pid_pmt & 0xff ;
crc = crc32_be ( ~ 0 , & localPAT [ 7 ] , sizeof ( PAT ) - 7 - 4 ) ;
localPAT [ sizeof ( PAT ) - 4 ] = ( crc > > 24 ) & 0xFF ;
localPAT [ sizeof ( PAT ) - 3 ] = ( crc > > 16 ) & 0xFF ;
localPAT [ sizeof ( PAT ) - 2 ] = ( crc > > 8 ) & 0xFF ;
localPAT [ sizeof ( PAT ) - 1 ] = crc & 0xFF ;
/* compute PMT */
2008-08-08 20:27:16 +04:00
if ( h - > params . au_encoding = = V4L2_MPEG_AUDIO_ENCODING_AC3 ) {
size = sizeof ( PMT_AC3 ) ;
memcpy ( localPMT , PMT_AC3 , size ) ;
} else {
size = sizeof ( PMT ) ;
memcpy ( localPMT , PMT , size ) ;
}
2005-11-09 08:37:43 +03:00
localPMT [ 3 ] = 0x40 | ( ( h - > params . ts_pid_pmt > > 8 ) & 0x0f ) ;
localPMT [ 4 ] = h - > params . ts_pid_pmt & 0xff ;
2005-04-17 02:20:36 +04:00
localPMT [ 15 ] = 0xE0 | ( ( h - > params . ts_pid_pcr > > 8 ) & 0x0F ) ;
localPMT [ 16 ] = h - > params . ts_pid_pcr & 0xFF ;
localPMT [ 20 ] = 0xE0 | ( ( h - > params . ts_pid_video > > 8 ) & 0x0F ) ;
localPMT [ 21 ] = h - > params . ts_pid_video & 0xFF ;
localPMT [ 25 ] = 0xE0 | ( ( h - > params . ts_pid_audio > > 8 ) & 0x0F ) ;
localPMT [ 26 ] = h - > params . ts_pid_audio & 0xFF ;
2008-08-08 20:27:16 +04:00
crc = crc32_be ( ~ 0 , & localPMT [ 7 ] , size - 7 - 4 ) ;
localPMT [ size - 4 ] = ( crc > > 24 ) & 0xFF ;
localPMT [ size - 3 ] = ( crc > > 16 ) & 0xFF ;
localPMT [ size - 2 ] = ( crc > > 8 ) & 0xFF ;
localPMT [ size - 1 ] = crc & 0xFF ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set Audio PID */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xc1 , h - > params . ts_pid_audio ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* Set Video PID */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xc0 , h - > params . ts_pid_video ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:37:43 +03:00
/* Set PCR PID */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xc4 , h - > params . ts_pid_pcr ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* Send SI tables */
2008-08-08 20:27:16 +04:00
i2c_master_send ( client , localPAT , sizeof ( PAT ) ) ;
i2c_master_send ( client , localPMT , size ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* mute then unmute audio. This removes buzzing artefacts */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0xa4 , 1 ) ;
set_reg8 ( client , 0xa4 , 0 ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* start it going */
2005-04-17 02:20:36 +04:00
saa6752hs_chip_command ( client , SAA6752HS_COMMAND_START ) ;
2005-11-09 08:36:45 +03:00
/* readout current state */
2005-04-17 02:20:36 +04:00
buf [ 0 ] = 0xE1 ;
buf [ 1 ] = 0xA7 ;
buf [ 2 ] = 0xFE ;
buf [ 3 ] = 0x82 ;
buf [ 4 ] = 0xB0 ;
i2c_master_send ( client , buf , 5 ) ;
i2c_master_recv ( client , buf2 , 4 ) ;
2005-11-09 08:36:45 +03:00
/* change aspect ratio */
2005-04-17 02:20:36 +04:00
buf [ 0 ] = 0xE0 ;
buf [ 1 ] = 0xA7 ;
buf [ 2 ] = 0xFE ;
buf [ 3 ] = 0x82 ;
buf [ 4 ] = 0xB0 ;
buf [ 5 ] = buf2 [ 0 ] ;
2009-01-14 12:54:38 +03:00
switch ( h - > params . vi_aspect ) {
2006-06-18 23:40:10 +04:00
case V4L2_MPEG_VIDEO_ASPECT_16x9 :
2005-04-17 02:20:36 +04:00
buf [ 6 ] = buf2 [ 1 ] | 0x40 ;
break ;
2006-06-18 23:40:10 +04:00
case V4L2_MPEG_VIDEO_ASPECT_4x3 :
2005-04-17 02:20:36 +04:00
default :
buf [ 6 ] = buf2 [ 1 ] & 0xBF ;
break ;
}
buf [ 7 ] = buf2 [ 2 ] ;
buf [ 8 ] = buf2 [ 3 ] ;
i2c_master_send ( client , buf , 9 ) ;
return 0 ;
}
2015-04-09 10:02:34 +03:00
static int saa6752hs_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 ,
2015-04-09 10:02:34 +03:00
struct v4l2_subdev_format * format )
2009-01-14 12:54:38 +03:00
{
2015-04-09 10:02:34 +03:00
struct v4l2_mbus_framefmt * f = & format - > format ;
2009-01-14 12:54:38 +03:00
struct saa6752hs_state * h = to_state ( sd ) ;
2008-08-08 19:43:59 +04:00
2015-04-09 10:02:34 +03:00
if ( format - > pad )
return - EINVAL ;
2009-01-14 12:54:38 +03:00
if ( h - > video_format = = SAA6752HS_VF_UNKNOWN )
h - > video_format = SAA6752HS_VF_D1 ;
2010-05-09 16:39:58 +04:00
f - > width = v4l2_format_table [ h - > video_format ] . fmt . pix . width ;
f - > height = v4l2_format_table [ h - > video_format ] . fmt . pix . height ;
2014-11-10 20:28:29 +03:00
f - > code = MEDIA_BUS_FMT_FIXED ;
2010-05-09 16:39:58 +04:00
f - > field = V4L2_FIELD_INTERLACED ;
f - > colorspace = V4L2_COLORSPACE_SMPTE170M ;
2009-01-14 12:54:38 +03:00
return 0 ;
}
2015-04-09 12:24:36 +03:00
static int saa6752hs_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 ,
2015-04-09 12:24:36 +03:00
struct v4l2_subdev_format * format )
2013-06-01 17:02:38 +04:00
{
2015-04-09 12:24:36 +03:00
struct v4l2_mbus_framefmt * f = & format - > format ;
struct saa6752hs_state * h = to_state ( sd ) ;
2013-06-01 17:02:38 +04:00
int dist_352 , dist_480 , dist_720 ;
2015-04-09 12:24:36 +03:00
if ( format - > pad )
return - EINVAL ;
2014-11-10 20:28:29 +03:00
f - > code = MEDIA_BUS_FMT_FIXED ;
2013-06-01 17:02:38 +04:00
dist_352 = abs ( f - > width - 352 ) ;
dist_480 = abs ( f - > width - 480 ) ;
dist_720 = abs ( f - > width - 720 ) ;
if ( dist_720 < dist_480 ) {
f - > width = 720 ;
f - > height = 576 ;
} else if ( dist_480 < dist_352 ) {
f - > width = 480 ;
f - > height = 576 ;
} else {
f - > width = 352 ;
if ( abs ( f - > height - 576 ) < abs ( f - > height - 288 ) )
f - > height = 576 ;
else
f - > height = 288 ;
}
f - > field = V4L2_FIELD_INTERLACED ;
f - > colorspace = V4L2_COLORSPACE_SMPTE170M ;
2015-04-09 12:24:36 +03:00
if ( format - > 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
sd_state - > pads - > try_fmt = * f ;
2015-04-09 12:24:36 +03:00
return 0 ;
}
2010-05-09 16:39:58 +04:00
2009-01-14 12:54:38 +03:00
/*
FIXME : translate and round width / height into EMPRESS
subsample type :
type | PAL | NTSC
- - - - - - - - - - - - - - - - - - - - - - - - - - -
SIF | 352 x288 | 352 x240
1 / 2 D1 | 352 x576 | 352 x480
2 / 3 D1 | 480 x576 | 480 x480
D1 | 720 x576 | 720 x480
*/
2015-04-09 12:24:36 +03:00
if ( f - > code ! = MEDIA_BUS_FMT_FIXED )
return - EINVAL ;
2013-06-01 17:02:38 +04:00
if ( f - > width = = 720 )
2009-01-14 12:54:38 +03:00
h - > video_format = SAA6752HS_VF_D1 ;
2013-06-01 17:02:38 +04:00
else if ( f - > width = = 480 )
2009-01-14 12:54:38 +03:00
h - > video_format = SAA6752HS_VF_2_3_D1 ;
2013-06-01 17:02:38 +04:00
else if ( f - > height = = 576 )
h - > video_format = SAA6752HS_VF_1_2_D1 ;
else
h - > video_format = SAA6752HS_VF_SIF ;
2009-01-14 12:54:38 +03:00
return 0 ;
}
static int saa6752hs_s_std ( struct v4l2_subdev * sd , v4l2_std_id std )
{
struct saa6752hs_state * h = to_state ( sd ) ;
h - > standard = std ;
return 0 ;
}
/* ----------------------------------------------------------------------- */
2013-06-10 11:51:42 +04:00
static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
. try_ctrl = saa6752hs_try_ctrl ,
. s_ctrl = saa6752hs_s_ctrl ,
} ;
2009-01-14 12:54:38 +03:00
static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
. init = saa6752hs_init ,
} ;
static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
2014-04-28 23:53:01 +04:00
. s_std = saa6752hs_s_std ,
2015-04-09 10:02:34 +03:00
} ;
static const struct v4l2_subdev_pad_ops saa6752hs_pad_ops = {
. get_fmt = saa6752hs_get_fmt ,
2015-04-09 12:24:36 +03:00
. set_fmt = saa6752hs_set_fmt ,
2009-01-14 12:54:38 +03:00
} ;
static const struct v4l2_subdev_ops saa6752hs_ops = {
. core = & saa6752hs_core_ops ,
. video = & saa6752hs_video_ops ,
2015-04-09 10:02:34 +03:00
. pad = & saa6752hs_pad_ops ,
2009-01-14 12:54:38 +03:00
} ;
2022-11-19 01:41:40 +03:00
static int saa6752hs_probe ( struct i2c_client * client )
2008-08-08 19:43:59 +04:00
{
2014-08-10 13:41:31 +04:00
struct saa6752hs_state * h ;
2009-01-14 12:54:38 +03:00
struct v4l2_subdev * sd ;
2013-06-10 11:51:42 +04:00
struct v4l2_ctrl_handler * hdl ;
2008-08-08 19:43:59 +04:00
u8 addr = 0x13 ;
u8 data [ 12 ] ;
2005-04-17 02:20:36 +04:00
2008-08-08 19:43:59 +04:00
v4l_info ( client , " chip found @ 0x%x (%s) \n " ,
client - > addr < < 1 , client - > adapter - > name ) ;
2014-08-10 13:41:31 +04:00
h = devm_kzalloc ( & client - > dev , sizeof ( * h ) , GFP_KERNEL ) ;
2008-08-08 19:43:59 +04:00
if ( h = = NULL )
return - ENOMEM ;
2009-01-14 12:54:38 +03:00
sd = & h - > sd ;
v4l2_i2c_subdev_init ( sd , client , & saa6752hs_ops ) ;
2005-04-17 02:20:36 +04:00
2008-08-08 19:43:59 +04:00
i2c_master_send ( client , & addr , 1 ) ;
i2c_master_recv ( client , data , sizeof ( data ) ) ;
h - > revision = ( data [ 8 ] < < 8 ) | data [ 9 ] ;
h - > has_ac3 = 0 ;
if ( h - > revision = = 0x0206 ) {
h - > has_ac3 = 1 ;
2013-06-10 11:51:42 +04:00
v4l_info ( client , " supports AC-3 \n " ) ;
2008-08-08 19:43:59 +04:00
}
h - > params = param_defaults ;
2013-06-10 11:51:42 +04:00
hdl = & h - > hdl ;
v4l2_ctrl_handler_init ( hdl , 14 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_AUDIO_ENCODING ,
h - > has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
V4L2_MPEG_AUDIO_ENCODING_LAYER_2 ,
0x0d , V4L2_MPEG_AUDIO_ENCODING_LAYER_2 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_AUDIO_L2_BITRATE ,
V4L2_MPEG_AUDIO_L2_BITRATE_384K ,
~ ( ( 1 < < V4L2_MPEG_AUDIO_L2_BITRATE_256K ) |
( 1 < < V4L2_MPEG_AUDIO_L2_BITRATE_384K ) ) ,
V4L2_MPEG_AUDIO_L2_BITRATE_256K ) ;
if ( h - > has_ac3 )
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_AUDIO_AC3_BITRATE ,
V4L2_MPEG_AUDIO_AC3_BITRATE_384K ,
~ ( ( 1 < < V4L2_MPEG_AUDIO_AC3_BITRATE_256K ) |
( 1 < < V4L2_MPEG_AUDIO_AC3_BITRATE_384K ) ) ,
V4L2_MPEG_AUDIO_AC3_BITRATE_256K ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ ,
V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 ,
~ ( 1 < < V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 ) ,
V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_ENCODING ,
V4L2_MPEG_VIDEO_ENCODING_MPEG_2 ,
~ ( 1 < < V4L2_MPEG_VIDEO_ENCODING_MPEG_2 ) ,
V4L2_MPEG_VIDEO_ENCODING_MPEG_2 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_ASPECT ,
V4L2_MPEG_VIDEO_ASPECT_16x9 , 0x01 ,
V4L2_MPEG_VIDEO_ASPECT_4x3 ) ;
h - > video_bitrate_peak = v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK ,
1000000 , 27000000 , 1000 , 8000000 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_TYPE ,
V4L2_MPEG_STREAM_TYPE_MPEG2_TS ,
~ ( 1 < < V4L2_MPEG_STREAM_TYPE_MPEG2_TS ) ,
V4L2_MPEG_STREAM_TYPE_MPEG2_TS ) ;
h - > video_bitrate_mode = v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_BITRATE_MODE ,
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR , 0 ,
V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ) ;
h - > video_bitrate = v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_BITRATE , 1000000 , 27000000 , 1000 , 6000000 ) ;
v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_PID_PMT , 0 , ( 1 < < 14 ) - 1 , 1 , 16 ) ;
v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_PID_AUDIO , 0 , ( 1 < < 14 ) - 1 , 1 , 260 ) ;
v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_PID_VIDEO , 0 , ( 1 < < 14 ) - 1 , 1 , 256 ) ;
v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_PID_PCR , 0 , ( 1 < < 14 ) - 1 , 1 , 259 ) ;
sd - > ctrl_handler = hdl ;
if ( hdl - > error ) {
int err = hdl - > error ;
v4l2_ctrl_handler_free ( hdl ) ;
return err ;
}
v4l2_ctrl_cluster ( 3 , & h - > video_bitrate_mode ) ;
v4l2_ctrl_handler_setup ( hdl ) ;
2008-08-08 19:43:59 +04:00
h - > standard = 0 ; /* Assume 625 input lines */
return 0 ;
2005-04-17 02:20:36 +04:00
}
2022-08-15 11:02:30 +03:00
static void saa6752hs_remove ( struct i2c_client * client )
2005-04-17 02:20:36 +04:00
{
2009-01-14 12:54:38 +03:00
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
v4l2_device_unregister_subdev ( sd ) ;
2013-06-10 11:51:42 +04:00
v4l2_ctrl_handler_free ( & to_state ( sd ) - > hdl ) ;
2005-04-17 02:20:36 +04:00
}
2008-08-08 19:43:59 +04:00
static const struct i2c_device_id saa6752hs_id [ ] = {
{ " saa6752hs " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , saa6752hs_id ) ;
2010-09-15 22:14:36 +04:00
static struct i2c_driver saa6752hs_driver = {
. driver = {
. name = " saa6752hs " ,
} ,
2022-11-19 01:41:40 +03:00
. probe_new = saa6752hs_probe ,
2010-09-15 22:14:36 +04:00
. remove = saa6752hs_remove ,
. id_table = saa6752hs_id ,
2008-08-08 19:43:59 +04:00
} ;
2005-04-17 02:20:36 +04:00
2012-02-12 13:56:32 +04:00
module_i2c_driver ( saa6752hs_driver ) ;