memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
ktime_get_ts(&dev->radio_rds_init_ts);
+ /* initialize locks */
+ spin_lock_init(&dev->slock);
+ mutex_init(&dev->mutex);
+ mutex_init(&dev->mutex_framerate);
+
/* create all controls */
ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj,
in_type_counter[TV] || in_type_counter[SVID] ||
dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
- /* initialize locks */
- spin_lock_init(&dev->slock);
- mutex_init(&dev->mutex);
-
/* init dma queues */
INIT_LIST_HEAD(&dev->vid_cap_active);
INIT_LIST_HEAD(&dev->vid_out_active);
struct v4l2_ctrl_handler ctrl_hdl_sdr_cap;
spinlock_t slock;
struct mutex mutex;
+ struct mutex mutex_framerate;
/* capabilities */
u32 vid_cap_caps;
struct v4l2_ctrl *colorspace;
struct v4l2_ctrl *rgb_range_cap;
struct v4l2_ctrl *real_rgb_range_cap;
+ struct v4l2_ctrl *framelength;
struct {
/* std_signal_mode/standard cluster */
struct v4l2_ctrl *ctrl_std_signal_mode;
if (dev->edid_blocks > dev->edid_max_blocks)
dev->edid_blocks = dev->edid_max_blocks;
break;
+ case VIVID_CID_FRAME_LENGTH:
+ vivid_update_timeperframe(dev, ctrl->val);
+ break;
}
return 0;
}
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_ycbcr_enc, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL);
- v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_framelength, NULL);
+ dev->framelength = v4l2_ctrl_new_custom(hdl_vid_cap,
+ &vivid_ctrl_framelength, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_coarsetime, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_coarsetime_short, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_grouphold, NULL);
break;
mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mutex_framerate);
cur_jiffies = jiffies;
if (dev->cap_seq_resync) {
dev->jiffies_vid_cap = cur_jiffies;
/* And the number of jiffies since we started */
jiffies_since_start = jiffies - dev->jiffies_vid_cap;
+ mutex_unlock(&dev->mutex_framerate);
mutex_unlock(&dev->mutex);
/*
break;
mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mutex_framerate);
cur_jiffies = jiffies;
if (dev->out_seq_resync) {
dev->jiffies_vid_out = cur_jiffies;
dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start;
vivid_thread_vid_out_tick(dev);
+ mutex_unlock(&dev->mutex_framerate);
mutex_unlock(&dev->mutex);
/*
return TPG_PIXEL_ASPECT_SQUARE;
}
+void vivid_update_timeperframe(struct vivid_dev *dev, u32 frame_length)
+{
+ struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+ unsigned size;
+
+ mutex_lock(&dev->mutex_framerate);
+
+ dev->cap_seq_resync = true;
+ size = V4L2_DV_BT_FRAME_WIDTH(bt) * frame_length;
+ dev->timeperframe_vid_cap = (struct v4l2_fract) {
+ size / 100, (u32)bt->pixelclock / 100
+ };
+
+ if (dev->loop_video) {
+ dev->out_seq_resync = true;
+ dev->timeperframe_vid_out = (struct v4l2_fract) {
+ size / 100, (u32)bt->pixelclock / 100
+ };
+ }
+
+ mutex_unlock(&dev->mutex_framerate);
+}
+
/*
* Called whenever the format has to be reset which can occur when
* changing inputs, standard, timings, etc.
dev->tv_field_cap = mp->field;
dev->fmt_cap->data_offset[0] = mp->width * dev->embedded_data_height;
tpg_update_mv_step(&dev->tpg);
+ // update framelength control to control framerate
+ v4l2_ctrl_s_ctrl(dev->framelength,
+ V4L2_DV_BT_FRAME_HEIGHT(&dev->dv_timings_cap.bt));
return 0;
}
dev->dv_timings_cap = *timings;
vivid_update_format_cap(dev, false);
+ // update framelength control to control framerate
+ v4l2_ctrl_s_ctrl(dev->framelength,
+ V4L2_DV_BT_FRAME_HEIGHT(&dev->dv_timings_cap.bt));
return 0;
}
int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival);
int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+void vivid_update_timeperframe(struct vivid_dev *dev, u32 frame_length);
#endif