Commit 448e1153 authored by Johan Korsnes's avatar Johan Korsnes Committed by Mauro Carvalho Chehab

media: vivid: make input dv_timings per-input

Make the following properties per-input

-DV Timings Signal Mode
-DV Timings

These properties need to be per-input in order to implement proper
HDMI (dis)connect-behavior, where the signal mode will be used to
signify whether or not there is an input device connected.
Signed-off-by: default avatarJohan Korsnes <johan.korsnes@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent b1b9b7be
...@@ -1005,7 +1005,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -1005,7 +1005,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
tvnorms_cap = V4L2_STD_ALL; tvnorms_cap = V4L2_STD_ALL;
if (dev->output_type[0] == SVID) if (dev->output_type[0] == SVID)
tvnorms_out = V4L2_STD_ALL; tvnorms_out = V4L2_STD_ALL;
dev->dv_timings_cap = def_dv_timings; for (i = 0; i < MAX_INPUTS; i++)
dev->dv_timings_cap[i] = def_dv_timings;
dev->dv_timings_out = def_dv_timings; dev->dv_timings_out = def_dv_timings;
dev->tv_freq = 2804 /* 175.25 * 16 */; dev->tv_freq = 2804 /* 175.25 * 16 */;
dev->tv_audmode = V4L2_TUNER_MODE_STEREO; dev->tv_audmode = V4L2_TUNER_MODE_STEREO;
...@@ -1035,6 +1036,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -1035,6 +1036,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret) if (ret)
goto unreg_dev; goto unreg_dev;
/* enable/disable interface specific controls */
if (dev->num_inputs && dev->input_type[0] != HDMI) {
v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false);
v4l2_ctrl_activate(dev->ctrl_dv_timings, false);
} else if (dev->num_inputs && dev->input_type[0] == HDMI) {
v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false);
v4l2_ctrl_activate(dev->ctrl_standard, false);
}
/* /*
* update the capture and output formats to do a proper initial * update the capture and output formats to do a proper initial
* configuration. * configuration.
......
...@@ -292,18 +292,19 @@ struct vivid_dev { ...@@ -292,18 +292,19 @@ struct vivid_dev {
v4l2_std_id query_std; v4l2_std_id query_std;
enum tpg_video_aspect std_aspect_ratio; enum tpg_video_aspect std_aspect_ratio;
enum vivid_signal_mode dv_timings_signal_mode; enum vivid_signal_mode dv_timings_signal_mode[MAX_INPUTS];
char **query_dv_timings_qmenu; char **query_dv_timings_qmenu;
char *query_dv_timings_qmenu_strings; char *query_dv_timings_qmenu_strings;
unsigned query_dv_timings_size; unsigned query_dv_timings_size;
unsigned query_dv_timings_last; unsigned int query_dv_timings_last[MAX_INPUTS];
unsigned query_dv_timings; unsigned int query_dv_timings[MAX_INPUTS];
enum tpg_video_aspect dv_timings_aspect_ratio; enum tpg_video_aspect dv_timings_aspect_ratio[MAX_INPUTS];
/* Input */ /* Input */
unsigned input; unsigned input;
v4l2_std_id std_cap; v4l2_std_id std_cap;
struct v4l2_dv_timings dv_timings_cap; struct v4l2_dv_timings dv_timings_cap[MAX_INPUTS];
int dv_timings_cap_sel[MAX_INPUTS];
u32 service_set_cap; u32 service_set_cap;
struct vivid_vbi_gen_data vbi_gen; struct vivid_vbi_gen_data vbi_gen;
u8 *edid; u8 *edid;
......
...@@ -467,16 +467,19 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) ...@@ -467,16 +467,19 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
break; break;
case VIVID_CID_DV_TIMINGS_SIGNAL_MODE: case VIVID_CID_DV_TIMINGS_SIGNAL_MODE:
dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val; dev->dv_timings_signal_mode[dev->input] =
if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) dev->ctrl_dv_timings_signal_mode->val;
dev->query_dv_timings = dev->ctrl_dv_timings->val; dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val;
v4l2_ctrl_activate(dev->ctrl_dv_timings, v4l2_ctrl_activate(dev->ctrl_dv_timings,
dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS); dev->dv_timings_signal_mode[dev->input] ==
SELECTED_DV_TIMINGS);
vivid_update_quality(dev); vivid_update_quality(dev);
vivid_send_source_change(dev, HDMI); vivid_send_source_change(dev, HDMI);
break; break;
case VIVID_CID_DV_TIMINGS_ASPECT_RATIO: case VIVID_CID_DV_TIMINGS_ASPECT_RATIO:
dev->dv_timings_aspect_ratio = ctrl->val; dev->dv_timings_aspect_ratio[dev->input] = ctrl->val;
tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
break; break;
case VIVID_CID_TSTAMP_SRC: case VIVID_CID_TSTAMP_SRC:
......
...@@ -421,7 +421,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) ...@@ -421,7 +421,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
((vivid_is_svid_cap(dev) && ((vivid_is_svid_cap(dev) &&
!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) || !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) ||
(vivid_is_hdmi_cap(dev) && (vivid_is_hdmi_cap(dev) &&
!VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)))) !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input]))))
is_loop = true; is_loop = true;
buf->vb.sequence = dev->vid_cap_seq_count; buf->vb.sequence = dev->vid_cap_seq_count;
......
...@@ -294,7 +294,8 @@ void vivid_update_quality(struct vivid_dev *dev) ...@@ -294,7 +294,8 @@ void vivid_update_quality(struct vivid_dev *dev)
tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
return; return;
} }
if (vivid_is_hdmi_cap(dev) && VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)) { if (vivid_is_hdmi_cap(dev) &&
VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])) {
tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
return; return;
} }
...@@ -356,7 +357,7 @@ enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) ...@@ -356,7 +357,7 @@ enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev)
return dev->std_aspect_ratio; return dev->std_aspect_ratio;
if (vivid_is_hdmi_cap(dev)) if (vivid_is_hdmi_cap(dev))
return dev->dv_timings_aspect_ratio; return dev->dv_timings_aspect_ratio[dev->input];
return TPG_VIDEO_ASPECT_IMAGE; return TPG_VIDEO_ASPECT_IMAGE;
} }
...@@ -381,7 +382,7 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) ...@@ -381,7 +382,7 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
*/ */
void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
{ {
struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;
unsigned size; unsigned size;
u64 pixelclock; u64 pixelclock;
...@@ -481,8 +482,8 @@ static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field fi ...@@ -481,8 +482,8 @@ static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field fi
} }
} }
if (vivid_is_hdmi_cap(dev)) if (vivid_is_hdmi_cap(dev))
return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE : return dev->dv_timings_cap[dev->input].bt.interlaced ?
V4L2_FIELD_NONE; V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE;
return V4L2_FIELD_NONE; return V4L2_FIELD_NONE;
} }
...@@ -1305,10 +1306,10 @@ int vidioc_enum_input(struct file *file, void *priv, ...@@ -1305,10 +1306,10 @@ int vidioc_enum_input(struct file *file, void *priv,
dev->input_name_counter[inp->index]); dev->input_name_counter[inp->index]);
inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
if (dev->edid_blocks == 0 || if (dev->edid_blocks == 0 ||
dev->dv_timings_signal_mode == NO_SIGNAL) dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL)
inp->status |= V4L2_IN_ST_NO_SIGNAL; inp->status |= V4L2_IN_ST_NO_SIGNAL;
else if (dev->dv_timings_signal_mode == NO_LOCK || else if (dev->dv_timings_signal_mode[dev->input] == NO_LOCK ||
dev->dv_timings_signal_mode == OUT_OF_RANGE) dev->dv_timings_signal_mode[dev->input] == OUT_OF_RANGE)
inp->status |= V4L2_IN_ST_NO_H_LOCK; inp->status |= V4L2_IN_ST_NO_H_LOCK;
break; break;
} }
...@@ -1348,7 +1349,7 @@ int vidioc_g_input(struct file *file, void *priv, unsigned *i) ...@@ -1348,7 +1349,7 @@ int vidioc_g_input(struct file *file, void *priv, unsigned *i)
int vidioc_s_input(struct file *file, void *priv, unsigned i) int vidioc_s_input(struct file *file, void *priv, unsigned i)
{ {
struct vivid_dev *dev = video_drvdata(file); struct vivid_dev *dev = video_drvdata(file);
struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;
unsigned brightness; unsigned brightness;
if (i >= dev->num_inputs) if (i >= dev->num_inputs)
...@@ -1402,6 +1403,20 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) ...@@ -1402,6 +1403,20 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
v4l2_ctrl_modify_range(dev->brightness, v4l2_ctrl_modify_range(dev->brightness,
128 * i, 255 + 128 * i, 1, 128 + 128 * i); 128 * i, 255 + 128 * i, 1, 128 + 128 * i);
v4l2_ctrl_s_ctrl(dev->brightness, brightness); v4l2_ctrl_s_ctrl(dev->brightness, brightness);
/* Restore per-input states. */
v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode,
vivid_is_hdmi_cap(dev));
v4l2_ctrl_activate(dev->ctrl_dv_timings, vivid_is_hdmi_cap(dev) &&
dev->dv_timings_signal_mode[dev->input] ==
SELECTED_DV_TIMINGS);
if (vivid_is_hdmi_cap(dev)) {
v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings_signal_mode,
dev->dv_timings_signal_mode[dev->input]);
v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings,
dev->query_dv_timings[dev->input]);
}
return 0; return 0;
} }
...@@ -1671,12 +1686,13 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, ...@@ -1671,12 +1686,13 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
!valid_cvt_gtf_timings(timings)) !valid_cvt_gtf_timings(timings))
return -EINVAL; return -EINVAL;
if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0, false)) if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap[dev->input],
0, false))
return 0; return 0;
if (vb2_is_busy(&dev->vb_vid_cap_q)) if (vb2_is_busy(&dev->vb_vid_cap_q))
return -EBUSY; return -EBUSY;
dev->dv_timings_cap = *timings; dev->dv_timings_cap[dev->input] = *timings;
vivid_update_format_cap(dev, false); vivid_update_format_cap(dev, false);
return 0; return 0;
} }
...@@ -1685,26 +1701,31 @@ int vidioc_query_dv_timings(struct file *file, void *_fh, ...@@ -1685,26 +1701,31 @@ int vidioc_query_dv_timings(struct file *file, void *_fh,
struct v4l2_dv_timings *timings) struct v4l2_dv_timings *timings)
{ {
struct vivid_dev *dev = video_drvdata(file); struct vivid_dev *dev = video_drvdata(file);
unsigned int input = dev->input;
unsigned int last = dev->query_dv_timings_last[input];
if (!vivid_is_hdmi_cap(dev)) if (!vivid_is_hdmi_cap(dev))
return -ENODATA; return -ENODATA;
if (dev->dv_timings_signal_mode == NO_SIGNAL || if (dev->dv_timings_signal_mode[input] == NO_SIGNAL ||
dev->edid_blocks == 0) dev->edid_blocks == 0)
return -ENOLINK; return -ENOLINK;
if (dev->dv_timings_signal_mode == NO_LOCK) if (dev->dv_timings_signal_mode[input] == NO_LOCK)
return -ENOLCK; return -ENOLCK;
if (dev->dv_timings_signal_mode == OUT_OF_RANGE) { if (dev->dv_timings_signal_mode[input] == OUT_OF_RANGE) {
timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2; timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2;
return -ERANGE; return -ERANGE;
} }
if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) { if (dev->dv_timings_signal_mode[input] == CURRENT_DV_TIMINGS) {
*timings = dev->dv_timings_cap; *timings = dev->dv_timings_cap[input];
} else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) { } else if (dev->dv_timings_signal_mode[input] ==
*timings = v4l2_dv_timings_presets[dev->query_dv_timings]; SELECTED_DV_TIMINGS) {
*timings =
v4l2_dv_timings_presets[dev->query_dv_timings[input]];
} else { } else {
*timings = v4l2_dv_timings_presets[dev->query_dv_timings_last]; *timings =
dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) % v4l2_dv_timings_presets[last];
dev->query_dv_timings_size; dev->query_dv_timings_last[input] =
(last + 1) % dev->query_dv_timings_size;
} }
return 0; return 0;
} }
......
...@@ -823,7 +823,7 @@ int vidioc_g_dv_timings(struct file *file, void *_fh, ...@@ -823,7 +823,7 @@ int vidioc_g_dv_timings(struct file *file, void *_fh,
if (vdev->vfl_dir == VFL_DIR_RX) { if (vdev->vfl_dir == VFL_DIR_RX) {
if (!vivid_is_hdmi_cap(dev)) if (!vivid_is_hdmi_cap(dev))
return -ENODATA; return -ENODATA;
*timings = dev->dv_timings_cap; *timings = dev->dv_timings_cap[dev->input];
} else { } else {
if (!vivid_is_hdmi_out(dev)) if (!vivid_is_hdmi_out(dev))
return -ENODATA; return -ENODATA;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment