/** * v4l2_m2m_get_vq() - return vb2_queue for the given type */ struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { struct v4l2_m2m_queue_ctx *q_ctx; q_ctx = get_queue_ctx(m2m_ctx, type); if (!q_ctx) return NULL; return &q_ctx->q; }
/** * v4l2_m2m_buf_queue() - add a buffer to the proper ready buffers list. * * Call from buf_queue(), videobuf_queue_ops callback. */ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb) { struct v4l2_m2m_buffer *b = container_of(vb, struct v4l2_m2m_buffer, vb); struct v4l2_m2m_queue_ctx *q_ctx; unsigned long flags; q_ctx = get_queue_ctx(m2m_ctx, vb->vb2_queue->type); if (!q_ctx) return; spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); list_add_tail(&b->list, &q_ctx->rdy_queue); q_ctx->num_rdy++; spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); }
/** * v4l2_m2m_buf_remove() - take off a buffer from the list of ready buffers and * return it */ void *v4l2_m2m_buf_remove(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { struct v4l2_m2m_queue_ctx *q_ctx; struct videobuf_buffer *vb = NULL; unsigned long flags; q_ctx = get_queue_ctx(m2m_ctx, type); if (!q_ctx) return NULL; spin_lock_irqsave(q_ctx->q.irqlock, flags); if (!list_empty(&q_ctx->rdy_queue)) { vb = list_entry(q_ctx->rdy_queue.next, struct videobuf_buffer, queue); list_del(&vb->queue); q_ctx->num_rdy--; }
/** * v4l2_m2m_next_buf() - return next buffer from the list of ready buffers */ void *v4l2_m2m_next_buf(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { struct v4l2_m2m_queue_ctx *q_ctx; struct videobuf_buffer *vb = NULL; unsigned long flags; q_ctx = get_queue_ctx(m2m_ctx, type); if (!q_ctx) return NULL; spin_lock_irqsave(q_ctx->q.irqlock, flags); if (list_empty(&q_ctx->rdy_queue)) goto end; vb = list_entry(q_ctx->rdy_queue.next, struct videobuf_buffer, queue); vb->state = VIDEOBUF_ACTIVE; end: spin_unlock_irqrestore(q_ctx->q.irqlock, flags); return vb; }
/** * v4l2_m2m_streamoff() - turn off streaming for a video queue */ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { struct v4l2_m2m_dev *m2m_dev; struct v4l2_m2m_queue_ctx *q_ctx; unsigned long flags_job, flags; int ret; /* wait until the current context is dequeued from job_queue */ v4l2_m2m_cancel_job(m2m_ctx); q_ctx = get_queue_ctx(m2m_ctx, type); ret = vb2_streamoff(&q_ctx->q, type); if (ret) return ret; m2m_dev = m2m_ctx->m2m_dev; spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job); /* We should not be scheduled anymore, since we're dropping a queue. */ if (m2m_ctx->job_flags & TRANS_QUEUED) list_del(&m2m_ctx->queue); m2m_ctx->job_flags = 0; spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); /* Drop queue, since streamoff returns device to the same state as after * calling reqbufs. */ INIT_LIST_HEAD(&q_ctx->rdy_queue); q_ctx->num_rdy = 0; spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); if (m2m_dev->curr_ctx == m2m_ctx) { m2m_dev->curr_ctx = NULL; wake_up(&m2m_ctx->finished); } spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); return 0; }