aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/vivid/vivid-vid-cap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/vivid/vivid-vid-cap.c')
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c142
1 files changed, 91 insertions, 51 deletions
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 530ac8decb25..8cbaa0c998ed 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -21,11 +21,6 @@
#include "vivid-kthread-cap.h"
#include "vivid-vid-cap.h"
-/* timeperframe: min/max and default */
-static const struct v4l2_fract
- tpf_min = {.numerator = 1, .denominator = FPS_MAX},
- tpf_max = {.numerator = FPS_MAX, .denominator = 1};
-
static const struct vivid_fmt formats_ovl[] = {
{
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
@@ -196,7 +191,7 @@ static void vid_cap_buf_finish(struct vb2_buffer *vb)
* test this.
*/
vbuf->flags |= V4L2_BUF_FLAG_TIMECODE;
- if (dev->std_cap & V4L2_STD_525_60)
+ if (dev->std_cap[dev->input] & V4L2_STD_525_60)
fps = 30;
tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS;
tc->flags = 0;
@@ -299,11 +294,13 @@ void vivid_update_quality(struct vivid_dev *dev)
tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
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);
return;
}
- if (vivid_is_sdtv_cap(dev) && VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+ if (vivid_is_sdtv_cap(dev) &&
+ VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) {
tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
return;
}
@@ -358,10 +355,10 @@ static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc)
enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev)
{
if (vivid_is_sdtv_cap(dev))
- return dev->std_aspect_ratio;
+ return dev->std_aspect_ratio[dev->input];
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;
}
@@ -369,7 +366,7 @@ enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev)
static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
{
if (vivid_is_sdtv_cap(dev))
- return (dev->std_cap & V4L2_STD_525_60) ?
+ return (dev->std_cap[dev->input] & V4L2_STD_525_60) ?
TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
if (vivid_is_hdmi_cap(dev) &&
@@ -386,7 +383,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)
{
- struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+ struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;
unsigned size;
u64 pixelclock;
@@ -403,7 +400,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
case SVID:
dev->field_cap = dev->tv_field_cap;
dev->src_rect.width = 720;
- if (dev->std_cap & V4L2_STD_525_60) {
+ if (dev->std_cap[dev->input] & V4L2_STD_525_60) {
dev->src_rect.height = 480;
dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 };
dev->service_set_cap = V4L2_SLICED_CAPTION_525;
@@ -486,8 +483,8 @@ static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field fi
}
}
if (vivid_is_hdmi_cap(dev))
- return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE :
- V4L2_FIELD_NONE;
+ return dev->dv_timings_cap[dev->input].bt.interlaced ?
+ V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE;
return V4L2_FIELD_NONE;
}
@@ -586,7 +583,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
h = sz->height;
} else if (vivid_is_sdtv_cap(dev)) {
w = 720;
- h = (dev->std_cap & V4L2_STD_525_60) ? 480 : 576;
+ h = (dev->std_cap[dev->input] & V4L2_STD_525_60) ? 480 : 576;
} else {
w = dev->src_rect.width;
h = dev->src_rect.height;
@@ -1310,10 +1307,10 @@ int vidioc_enum_input(struct file *file, void *priv,
dev->input_name_counter[inp->index]);
inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
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;
- else if (dev->dv_timings_signal_mode == NO_LOCK ||
- dev->dv_timings_signal_mode == OUT_OF_RANGE)
+ else if (dev->dv_timings_signal_mode[dev->input] == NO_LOCK ||
+ dev->dv_timings_signal_mode[dev->input] == OUT_OF_RANGE)
inp->status |= V4L2_IN_ST_NO_H_LOCK;
break;
}
@@ -1322,9 +1319,9 @@ int vidioc_enum_input(struct file *file, void *priv,
if (dev->sensor_vflip)
inp->status |= V4L2_IN_ST_VFLIP;
if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) {
- if (dev->std_signal_mode == NO_SIGNAL) {
+ if (dev->std_signal_mode[dev->input] == NO_SIGNAL) {
inp->status |= V4L2_IN_ST_NO_SIGNAL;
- } else if (dev->std_signal_mode == NO_LOCK) {
+ } else if (dev->std_signal_mode[dev->input] == NO_LOCK) {
inp->status |= V4L2_IN_ST_NO_H_LOCK;
} else if (vivid_is_tv_cap(dev)) {
switch (tpg_g_quality(&dev->tpg)) {
@@ -1353,7 +1350,7 @@ int vidioc_g_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 v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+ struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;
unsigned brightness;
if (i >= dev->num_inputs)
@@ -1407,6 +1404,29 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
v4l2_ctrl_modify_range(dev->brightness,
128 * i, 255 + 128 * i, 1, 128 + 128 * i);
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);
+ v4l2_ctrl_activate(dev->ctrl_std_signal_mode, vivid_is_sdtv_cap(dev));
+ v4l2_ctrl_activate(dev->ctrl_standard, vivid_is_sdtv_cap(dev) &&
+ dev->std_signal_mode[dev->input]);
+
+ 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]);
+ } else if (vivid_is_sdtv_cap(dev)) {
+ v4l2_ctrl_s_ctrl(dev->ctrl_std_signal_mode,
+ dev->std_signal_mode[dev->input]);
+ v4l2_ctrl_s_ctrl(dev->ctrl_standard,
+ dev->std_signal_mode[dev->input]);
+ }
+
return 0;
}
@@ -1499,8 +1519,9 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
} else if (qual == TPG_QUAL_GRAY) {
vt->rxsubchans = V4L2_TUNER_SUB_MONO;
} else {
- unsigned channel_nr = dev->tv_freq / (6 * 16);
- unsigned options = (dev->std_cap & V4L2_STD_NTSC_M) ? 4 : 3;
+ unsigned int channel_nr = dev->tv_freq / (6 * 16);
+ unsigned int options =
+ (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) ? 4 : 3;
switch (channel_nr % options) {
case 0:
@@ -1510,7 +1531,7 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
break;
case 2:
- if (dev->std_cap & V4L2_STD_NTSC_M)
+ if (dev->std_cap[dev->input] & V4L2_STD_NTSC_M)
vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP;
else
vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
@@ -1567,23 +1588,25 @@ const char * const vivid_ctrl_standard_strings[] = {
int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id)
{
struct vivid_dev *dev = video_drvdata(file);
+ unsigned int last = dev->query_std_last[dev->input];
if (!vivid_is_sdtv_cap(dev))
return -ENODATA;
- if (dev->std_signal_mode == NO_SIGNAL ||
- dev->std_signal_mode == NO_LOCK) {
+ if (dev->std_signal_mode[dev->input] == NO_SIGNAL ||
+ dev->std_signal_mode[dev->input] == NO_LOCK) {
*id = V4L2_STD_UNKNOWN;
return 0;
}
if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) {
*id = V4L2_STD_UNKNOWN;
- } else if (dev->std_signal_mode == CURRENT_STD) {
- *id = dev->std_cap;
- } else if (dev->std_signal_mode == SELECTED_STD) {
- *id = dev->query_std;
+ } else if (dev->std_signal_mode[dev->input] == CURRENT_STD) {
+ *id = dev->std_cap[dev->input];
+ } else if (dev->std_signal_mode[dev->input] == SELECTED_STD) {
+ *id = dev->query_std[dev->input];
} else {
- *id = vivid_standard[dev->query_std_last];
- dev->query_std_last = (dev->query_std_last + 1) % ARRAY_SIZE(vivid_standard);
+ *id = vivid_standard[last];
+ dev->query_std_last[dev->input] =
+ (last + 1) % ARRAY_SIZE(vivid_standard);
}
return 0;
@@ -1595,11 +1618,11 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id)
if (!vivid_is_sdtv_cap(dev))
return -ENODATA;
- if (dev->std_cap == id)
+ if (dev->std_cap[dev->input] == id)
return 0;
if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
return -EBUSY;
- dev->std_cap = id;
+ dev->std_cap[dev->input] = id;
vivid_update_format_cap(dev, false);
return 0;
}
@@ -1676,12 +1699,13 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
!valid_cvt_gtf_timings(timings))
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;
if (vb2_is_busy(&dev->vb_vid_cap_q))
return -EBUSY;
- dev->dv_timings_cap = *timings;
+ dev->dv_timings_cap[dev->input] = *timings;
vivid_update_format_cap(dev, false);
return 0;
}
@@ -1690,26 +1714,31 @@ int vidioc_query_dv_timings(struct file *file, void *_fh,
struct v4l2_dv_timings *timings)
{
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))
return -ENODATA;
- if (dev->dv_timings_signal_mode == NO_SIGNAL ||
+ if (dev->dv_timings_signal_mode[input] == NO_SIGNAL ||
dev->edid_blocks == 0)
return -ENOLINK;
- if (dev->dv_timings_signal_mode == NO_LOCK)
+ if (dev->dv_timings_signal_mode[input] == NO_LOCK)
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;
return -ERANGE;
}
- if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) {
- *timings = dev->dv_timings_cap;
- } else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) {
- *timings = v4l2_dv_timings_presets[dev->query_dv_timings];
+ if (dev->dv_timings_signal_mode[input] == CURRENT_DV_TIMINGS) {
+ *timings = dev->dv_timings_cap[input];
+ } else if (dev->dv_timings_signal_mode[input] ==
+ SELECTED_DV_TIMINGS) {
+ *timings =
+ v4l2_dv_timings_presets[dev->query_dv_timings[input]];
} else {
- *timings = v4l2_dv_timings_presets[dev->query_dv_timings_last];
- dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) %
- dev->query_dv_timings_size;
+ *timings =
+ v4l2_dv_timings_presets[last];
+ dev->query_dv_timings_last[input] =
+ (last + 1) % dev->query_dv_timings_size;
}
return 0;
}
@@ -1719,7 +1748,8 @@ int vidioc_s_edid(struct file *file, void *_fh,
{
struct vivid_dev *dev = video_drvdata(file);
u16 phys_addr;
- unsigned int i;
+ u32 display_present = 0;
+ unsigned int i, j;
int ret;
memset(edid->reserved, 0, sizeof(edid->reserved));
@@ -1729,6 +1759,8 @@ int vidioc_s_edid(struct file *file, void *_fh,
return -EINVAL;
if (edid->blocks == 0) {
dev->edid_blocks = 0;
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, 0);
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, 0);
phys_addr = CEC_PHYS_ADDR_INVALID;
goto set_phys_addr;
}
@@ -1747,13 +1779,23 @@ int vidioc_s_edid(struct file *file, void *_fh,
dev->edid_blocks = edid->blocks;
memcpy(dev->edid, edid->edid, edid->blocks * 128);
+ for (i = 0, j = 0; i < dev->num_outputs; i++)
+ if (dev->output_type[i] == HDMI)
+ display_present |=
+ dev->display_present[i] << j++;
+
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present);
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present);
+
set_phys_addr:
/* TODO: a proper hotplug detect cycle should be emulated here */
cec_s_phys_addr(dev->cec_rx_adap, phys_addr, false);
for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
cec_s_phys_addr(dev->cec_tx_adap[i],
- v4l2_phys_addr_for_input(phys_addr, i + 1),
+ dev->display_present[i] ?
+ v4l2_phys_addr_for_input(phys_addr, i + 1) :
+ CEC_PHYS_ADDR_INVALID,
false);
return 0;
}
@@ -1865,8 +1907,6 @@ int vivid_vid_cap_s_parm(struct file *file, void *priv,
i = ival_sz - 1;
dev->webcam_ival_idx = i;
tpf = webcam_intervals[dev->webcam_ival_idx];
- tpf = V4L2_FRACT_COMPARE(tpf, <, tpf_min) ? tpf_min : tpf;
- tpf = V4L2_FRACT_COMPARE(tpf, >, tpf_max) ? tpf_max : tpf;
/* resync the thread's timings */
dev->cap_seq_resync = true;