/** * v4l2_m2m_job_finish() - inform the framework that a job has been finished * and have it clean up * * Called by a driver to yield back the device after it has finished with it. * Should be called as soon as possible after reaching a state which allows * other instances to take control of the device. * * This function has to be called only after device_run() callback has been * called on the driver. To prevent recursion, it should not be called directly * from the device_run() callback though. */ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, struct v4l2_m2m_ctx *m2m_ctx) { unsigned long flags; spin_lock_irqsave(&m2m_dev->job_spinlock, flags); if (!m2m_dev->curr_ctx || m2m_dev->curr_ctx != m2m_ctx) { spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); dprintk("Called by an instance not currently running\n"); return; } list_del(&m2m_dev->curr_ctx->queue); m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING); wake_up(&m2m_dev->curr_ctx->finished); m2m_dev->curr_ctx = NULL; spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); /* This instance might have more buffers ready, but since we do not * allow more than one job on the job_queue per instance, each has * to be scheduled separately after the previous one finishes. */ v4l2_m2m_try_schedule(m2m_ctx); v4l2_m2m_try_run(m2m_dev); }
/** * v4l2_m2m_streamon() - turn on streaming for a video queue */ int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { struct vb2_queue *vq; int ret; vq = v4l2_m2m_get_vq(m2m_ctx, type); ret = vb2_streamon(vq, type); if (!ret) v4l2_m2m_try_schedule(m2m_ctx); return ret; }
/** * v4l2_m2m_qbuf() - enqueue a source or destination buffer, depending on * the type */ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_buffer *buf) { struct vb2_queue *vq; int ret; vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); ret = vb2_qbuf(vq, buf); if (!ret) v4l2_m2m_try_schedule(m2m_ctx); return ret; }
static int vidioc_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); struct vb2_queue *src_vq, *dst_vq; int ret; ret = vidioc_try_decoder_cmd(file, priv, cmd); if (ret) return ret; mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd); dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); switch (cmd->cmd) { case V4L2_DEC_CMD_STOP: src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); if (!vb2_is_streaming(src_vq)) { mtk_v4l2_debug(1, "Output stream is off. No need to flush."); return 0; } if (!vb2_is_streaming(dst_vq)) { mtk_v4l2_debug(1, "Capture stream is off. No need to flush."); return 0; } v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf->vb); v4l2_m2m_try_schedule(ctx->m2m_ctx); break; case V4L2_DEC_CMD_START: vb2_clear_last_buffer_dequeued(dst_vq); break; default: return -EINVAL; } return 0; }
static void gsc_m2m_fence_work(struct work_struct *work) { struct gsc_ctx *ctx = container_of(work, struct gsc_ctx, fence_work); struct v4l2_m2m_buffer *buffer; struct sync_fence *fence; unsigned long flags; int ret; spin_lock_irqsave(&ctx->slock, flags); while (!list_empty(&ctx->fence_wait_list)) { buffer = list_first_entry(&ctx->fence_wait_list, struct v4l2_m2m_buffer, wait); list_del(&buffer->wait); spin_unlock_irqrestore(&ctx->slock, flags); fence = buffer->vb.acquire_fence; if (fence) { buffer->vb.acquire_fence = NULL; ret = sync_fence_wait(fence, 1000); if (ret == -ETIME) { gsc_warn("sync_fence_wait() timeout"); ret = sync_fence_wait(fence, 10 * MSEC_PER_SEC); } if (ret) gsc_warn("sync_fence_wait() error"); sync_fence_put(fence); } if (ctx->m2m_ctx) { v4l2_m2m_buf_queue(ctx->m2m_ctx, &buffer->vb); v4l2_m2m_try_schedule(ctx->m2m_ctx); } spin_lock_irqsave(&ctx->slock, flags); } spin_unlock_irqrestore(&ctx->slock, flags); }