diff options
Diffstat (limited to 'drivers/media/platform/vivid/vivid-vid-cap.c')
-rw-r--r-- | drivers/media/platform/vivid/vivid-vid-cap.c | 142 |
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; |