static int isp_video_buffer_prepare(struct vb2_buffer *buf)
{
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf);
	struct isp_video_fh *vfh = vb2_get_drv_priv(buf->vb2_queue);
	struct isp_buffer *buffer = to_isp_buffer(vbuf);
	struct isp_video *video = vfh->video;
	dma_addr_t addr;

	/* Refuse to prepare the buffer is the video node has registered an
	 * error. We don't need to take any lock here as the operation is
	 * inherently racy. The authoritative check will be performed in the
	 * queue handler, which can't return an error, this check is just a best
	 * effort to notify userspace as early as possible.
	 */
	if (unlikely(video->error))
		return -EIO;

	addr = vb2_dma_contig_plane_dma_addr(buf, 0);
	if (!IS_ALIGNED(addr, 32)) {
		dev_dbg(video->isp->dev,
			"Buffer address must be aligned to 32 bytes boundary.\n");
		return -EINVAL;
	}

	vb2_set_plane_payload(&buffer->vb.vb2_buf, 0,
			      vfh->format.fmt.pix.sizeimage);
	buffer->dma = addr;

	return 0;
}
/*
 * isp_video_buffer_queue - Add buffer to streaming queue
 * @buf: Video buffer
 *
 * In memory-to-memory mode, start streaming on the pipeline if buffers are
 * queued on both the input and the output, if the pipeline isn't already busy.
 * If the pipeline is busy, it will be restarted in the output module interrupt
 * handler.
 */
static void isp_video_buffer_queue(struct isp_video_buffer *buf)
{
    struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
    struct isp_buffer *buffer = to_isp_buffer(buf);
    struct isp_video *video = vfh->video;
    struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
    enum isp_pipeline_state state;
    unsigned long flags;
    unsigned int empty;
    unsigned int start;

    empty = list_empty(&video->dmaqueue);
    list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);

    if (empty) {
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
            state = ISP_PIPELINE_QUEUE_OUTPUT;
        else
            state = ISP_PIPELINE_QUEUE_INPUT;

        spin_lock_irqsave(&pipe->lock, flags);
        pipe->state |= state;
        video->ops->queue(video, buffer);
        video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;

        start = isp_pipeline_ready(pipe);
        if (start)
            pipe->state |= ISP_PIPELINE_STREAM;
        spin_unlock_irqrestore(&pipe->lock, flags);

        if (start)
            omap3isp_pipeline_set_stream(pipe,
                                         ISP_PIPELINE_STREAM_SINGLESHOT);
    }
}
示例#3
0
文件: ispvideo.c 项目: borkmann/kasan
static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
{
    struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
    struct isp_buffer *buffer = to_isp_buffer(buf);
    struct isp_video *video = vfh->video;
    unsigned long addr;

    /* Refuse to prepare the buffer is the video node has registered an
     * error. We don't need to take any lock here as the operation is
     * inherently racy. The authoritative check will be performed in the
     * queue handler, which can't return an error, this check is just a best
     * effort to notify userspace as early as possible.
     */
    if (unlikely(video->error))
        return -EIO;

    addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
    if (IS_ERR_VALUE(addr))
        return -EIO;

    if (!IS_ALIGNED(addr, 32)) {
        dev_dbg(video->isp->dev, "Buffer address must be "
                "aligned to 32 bytes boundary.\n");
        ispmmu_vunmap(video->isp, buffer->isp_addr);
        return -EINVAL;
    }

    buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
    buffer->isp_addr = addr;
    return 0;
}
static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
{
    struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
    struct isp_buffer *buffer = to_isp_buffer(buf);
    struct isp_video *video = vfh->video;

    if (buffer->isp_addr) {
        ispmmu_vunmap(video->isp, buffer->isp_addr);
        buffer->isp_addr = 0;
    }
}
示例#5
0
/*
 * isp_video_buffer_next - Complete the current buffer and return the next one
 * @video: ISP video object
 * @error: Whether an error occured during capture
 *
 * Remove the current video buffer from the DMA queue and fill its timestamp,
 * field count and state fields before waking up its completion handler.
 *
 * The buffer state is set to VIDEOBUF_DONE if no error occured (@error is 0)
 * or VIDEOBUF_ERROR otherwise (@error is non-zero).
 *
 * The DMA queue is expected to contain at least one buffer.
 *
 * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
 * empty.
 */
struct isp_buffer *isp_video_buffer_next(struct isp_video *video,
					 unsigned int error)
{
	struct isp_video_queue *queue = video->queue;
	enum isp_pipeline_state state;
	struct isp_video_buffer *buf;
	unsigned long flags;
	struct timespec ts;

	spin_lock_irqsave(&queue->irqlock, flags);
	BUG_ON(list_empty(&video->dmaqueue));
	buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
			       irqlist);
	list_del(&buf->irqlist);
	spin_unlock_irqrestore(&queue->irqlock, flags);

	ktime_get_ts(&ts);
	buf->vbuf.timestamp.tv_sec = ts.tv_sec;
	buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;

	buf->vbuf.sequence = atomic_inc_return(&video->sequence);
	buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE;

	wake_up(&buf->wait);

	if (list_empty(&video->dmaqueue)) {
		if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
			state = ISP_PIPELINE_QUEUE_OUTPUT
			      | ISP_PIPELINE_STREAM;
		else
			state = ISP_PIPELINE_QUEUE_INPUT
			      | ISP_PIPELINE_STREAM;

		spin_lock_irqsave(&video->pipe->lock, flags);
		video->pipe->state &= ~state;
		spin_unlock_irqrestore(&video->pipe->lock, flags);
		return NULL;
	}

	if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
	    video->pipe->input != NULL) {
		spin_lock_irqsave(&video->pipe->lock, flags);
		video->pipe->state &= ~ISP_PIPELINE_STREAM;
		spin_unlock_irqrestore(&video->pipe->lock, flags);
	}

	buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
			       irqlist);
	buf->state = ISP_BUF_STATE_ACTIVE;
	return to_isp_buffer(buf);
}
/*
 * isp_video_buffer_queue - Add buffer to streaming queue
 * @buf: Video buffer
 *
 * In memory-to-memory mode, start streaming on the pipeline if buffers are
 * queued on both the input and the output, if the pipeline isn't already busy.
 * If the pipeline is busy, it will be restarted in the output module interrupt
 * handler.
 */
static void isp_video_buffer_queue(struct vb2_buffer *buf)
{
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf);
	struct isp_video_fh *vfh = vb2_get_drv_priv(buf->vb2_queue);
	struct isp_buffer *buffer = to_isp_buffer(vbuf);
	struct isp_video *video = vfh->video;
	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
	enum isp_pipeline_state state;
	unsigned long flags;
	unsigned int empty;
	unsigned int start;

	spin_lock_irqsave(&video->irqlock, flags);

	if (unlikely(video->error)) {
		vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_ERROR);
		spin_unlock_irqrestore(&video->irqlock, flags);
		return;
	}

	empty = list_empty(&video->dmaqueue);
	list_add_tail(&buffer->irqlist, &video->dmaqueue);

	spin_unlock_irqrestore(&video->irqlock, flags);

	if (empty) {
		if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
			state = ISP_PIPELINE_QUEUE_OUTPUT;
		else
			state = ISP_PIPELINE_QUEUE_INPUT;

		spin_lock_irqsave(&pipe->lock, flags);
		pipe->state |= state;
		video->ops->queue(video, buffer);
		video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;

		start = isp_pipeline_ready(pipe);
		if (start)
			pipe->state |= ISP_PIPELINE_STREAM;
		spin_unlock_irqrestore(&pipe->lock, flags);

		if (start)
			omap3isp_pipeline_set_stream(pipe,
						ISP_PIPELINE_STREAM_SINGLESHOT);
	}
}
static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
{
    struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
    struct isp_buffer *buffer = to_isp_buffer(buf);
    struct isp_video *video = vfh->video;
    unsigned long addr;

    addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
    if (IS_ERR_VALUE(addr))
        return -EIO;

    if (!IS_ALIGNED(addr, 32)) {
        dev_dbg(video->isp->dev, "Buffer address must be "
                "aligned to 32 bytes boundary.\n");
        ispmmu_vunmap(video->isp, buffer->isp_addr);
        return -EINVAL;
    }

    buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
    buffer->isp_addr = addr;
    return 0;
}
/*
 * omap3isp_video_buffer_next - Complete the current buffer and return the next
 * @video: ISP video object
 * @error: Whether an error occurred during capture
 *
 * Remove the current video buffer from the DMA queue and fill its timestamp,
 * field count and state fields before waking up its completion handler.
 *
 * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0)
 * or VIDEOBUF_ERROR otherwise (@error is non-zero).
 *
 * The DMA queue is expected to contain at least one buffer.
 *
 * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
 * empty.
 */
struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
        unsigned int error)
{
    struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
    struct isp_video_queue *queue = video->queue;
    enum isp_pipeline_state state;
    struct isp_video_buffer *buf;
    unsigned long flags;
    struct timespec ts;

    spin_lock_irqsave(&queue->irqlock, flags);
    if (WARN_ON(list_empty(&video->dmaqueue))) {
        spin_unlock_irqrestore(&queue->irqlock, flags);
        return NULL;
    }

    buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
                           irqlist);
    list_del(&buf->irqlist);
    spin_unlock_irqrestore(&queue->irqlock, flags);

    ktime_get_ts(&ts);
    buf->vbuf.timestamp.tv_sec = ts.tv_sec;
    buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;

    /* Do frame number propagation only if this is the output video node.
     * Frame number either comes from the CSI receivers or it gets
     * incremented here if H3A is not active.
     * Note: There is no guarantee that the output buffer will finish
     * first, so the input number might lag behind by 1 in some cases.
     */
    if (video == pipe->output && !pipe->do_propagation)
        buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number);
    else
        buf->vbuf.sequence = atomic_read(&pipe->frame_number);

    buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE;

    wake_up(&buf->wait);

    if (list_empty(&video->dmaqueue)) {
        if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
            state = ISP_PIPELINE_QUEUE_OUTPUT
                    | ISP_PIPELINE_STREAM;
        else
            state = ISP_PIPELINE_QUEUE_INPUT
                    | ISP_PIPELINE_STREAM;

        spin_lock_irqsave(&pipe->lock, flags);
        pipe->state &= ~state;
        if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS)
            video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
        spin_unlock_irqrestore(&pipe->lock, flags);
        return NULL;
    }

    if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
        spin_lock_irqsave(&pipe->lock, flags);
        pipe->state &= ~ISP_PIPELINE_STREAM;
        spin_unlock_irqrestore(&pipe->lock, flags);
    }

    buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
                           irqlist);
    buf->state = ISP_BUF_STATE_ACTIVE;
    return to_isp_buffer(buf);
}