summaryrefslogtreecommitdiff
path: root/drivers/media/test-drivers/vivid/vivid-vid-cap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/test-drivers/vivid/vivid-vid-cap.c')
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c148
1 files changed, 96 insertions, 52 deletions
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index 2804975fe278..84e9155b5815 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/videodev2.h>
+#include <linux/prandom.h>
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
@@ -24,16 +25,18 @@
/* Sizes must be in increasing order */
static const struct v4l2_frmsize_discrete webcam_sizes[] = {
{ 320, 180 },
+ { 320, 240 },
{ 640, 360 },
{ 640, 480 },
{ 1280, 720 },
+ { 1280, 960 },
+ { 1600, 1200 },
{ 1920, 1080 },
{ 3840, 2160 },
};
/*
- * Intervals must be in increasing order and there must be twice as many
- * elements in this array as there are in webcam_sizes.
+ * Intervals must be in increasing order.
*/
static const struct v4l2_fract webcam_intervals[] = {
{ 1, 1 },
@@ -106,8 +109,9 @@ static int vid_cap_queue_setup(struct vb2_queue *vq,
if (*nplanes != buffers)
return -EINVAL;
for (p = 0; p < buffers; p++) {
- if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h +
- dev->fmt_cap->data_offset[p])
+ if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h /
+ dev->fmt_cap->vdownsampling[p] +
+ dev->fmt_cap->data_offset[p])
return -EINVAL;
}
} else {
@@ -210,12 +214,9 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
unsigned i;
int err;
- if (vb2_is_streaming(&dev->vb_vid_out_q))
- dev->can_loop_video = vivid_vid_can_loop(dev);
-
dev->vid_cap_seq_count = 0;
dprintk(dev, 1, "%s\n", __func__);
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ for (i = 0; i < MAX_VID_CAP_BUFFERS; i++)
dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100;
if (dev->start_streaming_error) {
dev->start_streaming_error = false;
@@ -242,7 +243,6 @@ static void vid_cap_stop_streaming(struct vb2_queue *vq)
dprintk(dev, 1, "%s\n", __func__);
vivid_stop_generating_vid_cap(dev, &dev->vid_cap_streaming);
- dev->can_loop_video = false;
}
static void vid_cap_buf_request_complete(struct vb2_buffer *vb)
@@ -260,8 +260,6 @@ const struct vb2_ops vivid_vid_cap_qops = {
.start_streaming = vid_cap_start_streaming,
.stop_streaming = vid_cap_stop_streaming,
.buf_request_complete = vid_cap_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/*
@@ -273,7 +271,7 @@ void vivid_update_quality(struct vivid_dev *dev)
{
unsigned freq_modulus;
- if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) {
+ if (dev->input_is_connected_to_output[dev->input]) {
/*
* The 'noise' will only be replaced by the actual video
* if the output video matches the input video settings.
@@ -487,35 +485,35 @@ static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field fi
static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_colorspace(&dev->tpg);
return dev->colorspace_out;
}
static unsigned vivid_xfer_func_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_xfer_func(&dev->tpg);
return dev->xfer_func_out;
}
static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_ycbcr_enc(&dev->tpg);
return dev->ycbcr_enc_out;
}
static unsigned int vivid_hsv_enc_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_hsv_enc(&dev->tpg);
return dev->hsv_enc_out;
}
static unsigned vivid_quantization_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_quantization(&dev->tpg);
return dev->quantization_out;
}
@@ -950,8 +948,8 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
if (dev->has_compose_cap) {
v4l2_rect_set_min_size(compose, &min_rect);
v4l2_rect_set_max_size(compose, &max_rect);
- v4l2_rect_map_inside(compose, &fmt);
}
+ v4l2_rect_map_inside(compose, &fmt);
dev->fmt_cap_rect = fmt;
tpg_s_buf_height(&dev->tpg, fmt.height);
} else if (dev->has_compose_cap) {
@@ -1072,13 +1070,13 @@ int vidioc_enum_input(struct file *file, void *priv,
inp->type = V4L2_INPUT_TYPE_CAMERA;
switch (dev->input_type[inp->index]) {
case WEBCAM:
- snprintf(inp->name, sizeof(inp->name), "Webcam %u",
- dev->input_name_counter[inp->index]);
+ snprintf(inp->name, sizeof(inp->name), "Webcam %03u-%u",
+ dev->inst, dev->input_name_counter[inp->index]);
inp->capabilities = 0;
break;
case TV:
- snprintf(inp->name, sizeof(inp->name), "TV %u",
- dev->input_name_counter[inp->index]);
+ snprintf(inp->name, sizeof(inp->name), "TV %03u-%u",
+ dev->inst, dev->input_name_counter[inp->index]);
inp->type = V4L2_INPUT_TYPE_TUNER;
inp->std = V4L2_STD_ALL;
if (dev->has_audio_inputs)
@@ -1086,16 +1084,16 @@ int vidioc_enum_input(struct file *file, void *priv,
inp->capabilities = V4L2_IN_CAP_STD;
break;
case SVID:
- snprintf(inp->name, sizeof(inp->name), "S-Video %u",
- dev->input_name_counter[inp->index]);
+ snprintf(inp->name, sizeof(inp->name), "S-Video %03u-%u",
+ dev->inst, dev->input_name_counter[inp->index]);
inp->std = V4L2_STD_ALL;
if (dev->has_audio_inputs)
inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1;
inp->capabilities = V4L2_IN_CAP_STD;
break;
case HDMI:
- snprintf(inp->name, sizeof(inp->name), "HDMI %u",
- dev->input_name_counter[inp->index]);
+ snprintf(inp->name, sizeof(inp->name), "HDMI %03u-%u",
+ dev->inst, dev->input_name_counter[inp->index]);
inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
if (dev->edid_blocks == 0 ||
dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL)
@@ -1462,12 +1460,19 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings)
h_freq = (u32)bt->pixelclock / total_h_pixel;
if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) {
+ struct v4l2_dv_timings cvt = {};
+
if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width,
- bt->polarities, bt->interlaced, timings))
+ bt->polarities, bt->interlaced,
+ &vivid_dv_timings_cap, &cvt) &&
+ cvt.bt.width == bt->width && cvt.bt.height == bt->height) {
+ *timings = cvt;
return true;
+ }
}
if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) {
+ struct v4l2_dv_timings gtf = {};
struct v4l2_fract aspect_ratio;
find_aspect_ratio(bt->width, bt->height,
@@ -1475,8 +1480,12 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings)
&aspect_ratio.denominator);
if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync,
bt->polarities, bt->interlaced,
- aspect_ratio, timings))
+ aspect_ratio, &vivid_dv_timings_cap,
+ &gtf) &&
+ gtf.bt.width == bt->width && gtf.bt.height == bt->height) {
+ *timings = gtf;
return true;
+ }
}
return false;
}
@@ -1537,13 +1546,65 @@ int vidioc_query_dv_timings(struct file *file, void *_fh,
return 0;
}
+void vivid_update_outputs(struct vivid_dev *dev)
+{
+ u32 edid_present = 0;
+
+ if (!dev || !dev->num_outputs)
+ return;
+ for (unsigned int i = 0, j = 0; i < dev->num_outputs; i++) {
+ if (dev->output_type[i] != HDMI)
+ continue;
+
+ struct vivid_dev *dev_rx = dev->output_to_input_instance[i];
+
+ if (dev_rx && dev_rx->edid_blocks)
+ edid_present |= 1 << j;
+ j++;
+ }
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, edid_present);
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, edid_present);
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, edid_present);
+}
+
+void vivid_update_connected_outputs(struct vivid_dev *dev)
+{
+ u16 phys_addr = cec_get_edid_phys_addr(dev->edid, dev->edid_blocks * 128, NULL);
+
+ for (unsigned int i = 0, j = 0; i < dev->num_inputs; i++) {
+ unsigned int menu_idx =
+ dev->input_is_connected_to_output[i];
+
+ if (dev->input_type[i] != HDMI)
+ continue;
+ j++;
+ if (menu_idx < FIXED_MENU_ITEMS)
+ continue;
+
+ struct vivid_dev *dev_tx = vivid_ctrl_hdmi_to_output_instance[menu_idx];
+ unsigned int output = vivid_ctrl_hdmi_to_output_index[menu_idx];
+
+ if (!dev_tx)
+ continue;
+
+ unsigned int hdmi_output = dev_tx->output_to_iface_index[output];
+
+ vivid_update_outputs(dev_tx);
+ if (dev->edid_blocks) {
+ cec_s_phys_addr(dev_tx->cec_tx_adap[hdmi_output],
+ v4l2_phys_addr_for_input(phys_addr, j),
+ false);
+ } else {
+ cec_phys_addr_invalidate(dev_tx->cec_tx_adap[hdmi_output]);
+ }
+ }
+}
+
int vidioc_s_edid(struct file *file, void *_fh,
struct v4l2_edid *edid)
{
struct vivid_dev *dev = video_drvdata(file);
u16 phys_addr;
- u32 display_present = 0;
- unsigned int i, j;
int ret;
memset(edid->reserved, 0, sizeof(edid->reserved));
@@ -1552,11 +1613,11 @@ int vidioc_s_edid(struct file *file, void *_fh,
if (dev->input_type[edid->pad] != HDMI || edid->start_block)
return -EINVAL;
if (edid->blocks == 0) {
+ if (vb2_is_busy(&dev->vb_vid_cap_q))
+ return -EBUSY;
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;
+ vivid_update_connected_outputs(dev);
+ return 0;
}
if (edid->blocks > dev->edid_max_blocks) {
edid->blocks = dev->edid_max_blocks;
@@ -1573,24 +1634,7 @@ 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],
- dev->display_present[i] ?
- v4l2_phys_addr_for_input(phys_addr, i + 1) :
- CEC_PHYS_ADDR_INVALID,
- false);
+ vivid_update_connected_outputs(dev);
return 0;
}